shlwapi: Add tests for PathCombineA.
[wine/dcerpc.git] / dlls / msi / action.c
bloba953da4cac4ec6c6a6c10d846a7043a3fe6049b0
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 int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
297 LPWSTR str = msi_dup_property( package, prop );
298 int val = str ? atoiW( str ) : def;
299 msi_free( str );
300 return val;
303 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
305 LPCWSTR ptr,ptr2;
306 BOOL quote;
307 DWORD len;
308 LPWSTR prop = NULL, val = NULL;
310 if (!szCommandLine)
311 return ERROR_SUCCESS;
313 ptr = szCommandLine;
315 while (*ptr)
317 if (*ptr==' ')
319 ptr++;
320 continue;
323 TRACE("Looking at %s\n",debugstr_w(ptr));
325 ptr2 = strchrW(ptr,'=');
326 if (!ptr2)
328 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
329 break;
332 quote = FALSE;
334 len = ptr2-ptr;
335 prop = msi_alloc((len+1)*sizeof(WCHAR));
336 memcpy(prop,ptr,len*sizeof(WCHAR));
337 prop[len]=0;
338 ptr2++;
340 len = 0;
341 ptr = ptr2;
342 while (*ptr && (quote || (!quote && *ptr!=' ')))
344 if (*ptr == '"')
345 quote = !quote;
346 ptr++;
347 len++;
350 if (*ptr2=='"')
352 ptr2++;
353 len -= 2;
355 val = msi_alloc((len+1)*sizeof(WCHAR));
356 memcpy(val,ptr2,len*sizeof(WCHAR));
357 val[len] = 0;
359 if (lstrlenW(prop) > 0)
361 TRACE("Found commandline property (%s) = (%s)\n",
362 debugstr_w(prop), debugstr_w(val));
363 MSI_SetPropertyW(package,prop,val);
365 msi_free(val);
366 msi_free(prop);
369 return ERROR_SUCCESS;
373 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
375 LPWSTR p, *ret = NULL;
376 UINT count = 0;
378 if (!str)
379 return ret;
381 /* count the number of substrings */
382 for ( p = (LPWSTR)str, count = 0; p; count++ )
384 p = strchrW( p, sep );
385 if (p)
386 p++;
389 /* allocate space for an array of substring pointers and the substrings */
390 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
391 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 if (!ret)
393 return ret;
395 /* copy the string and set the pointers */
396 p = (LPWSTR) &ret[count+1];
397 lstrcpyW( p, str );
398 for( count = 0; (ret[count] = p); count++ )
400 p = strchrW( p, sep );
401 if (p)
402 *p++ = 0;
405 return ret;
408 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
413 HRESULT r;
415 TRACE("%p %s\n", package, debugstr_w(name) );
417 if (*name++ != ':')
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
424 if (SUCCEEDED(r))
426 ret = msi_table_apply_transform( package->db, stg );
427 IStorage_Release( stg );
428 ret = ERROR_SUCCESS;
430 else
431 ERR("failed to open substorage %s\n", debugstr_w(name));
433 return ret;
436 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
438 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
439 LPWSTR guid_list, *guids, product_id;
440 UINT i, ret = ERROR_FUNCTION_FAILED;
442 product_id = msi_dup_property( package, szProdID );
443 if (!product_id)
445 /* FIXME: the property ProductID should be written into the DB somewhere */
446 ERR("no product ID to check\n");
447 return ERROR_SUCCESS;
450 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
451 guids = msi_split_string( guid_list, ';' );
452 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
454 if (!lstrcmpW( guids[i], product_id ))
455 ret = ERROR_SUCCESS;
457 msi_free( guids );
458 msi_free( guid_list );
459 msi_free( product_id );
461 return ret;
464 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
466 MSISUMMARYINFO *si;
467 LPWSTR str, *substorage;
468 UINT i, r = ERROR_SUCCESS;
470 si = MSI_GetSummaryInformationW( patch_db, 0 );
471 if (!si)
472 return ERROR_FUNCTION_FAILED;
474 msi_check_patch_applicable( package, si );
476 /* enumerate the substorage */
477 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
478 substorage = msi_split_string( str, ';' );
479 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
480 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
481 msi_free( substorage );
482 msi_free( str );
484 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
486 msiobj_release( &si->hdr );
488 return r;
491 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
493 MSIDATABASE *patch_db = NULL;
494 UINT r;
496 TRACE("%p %s\n", package, debugstr_w( file ) );
498 /* FIXME:
499 * We probably want to make sure we only open a patch collection here.
500 * Patch collections (.msp) and databases (.msi) have different GUIDs
501 * but currently MSI_OpenDatabaseW will accept both.
503 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
504 if ( r != ERROR_SUCCESS )
506 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
507 return r;
510 msi_parse_patch_summary( package, patch_db );
511 msiobj_release( &patch_db->hdr );
513 return ERROR_SUCCESS;
516 /* get the PATCH property, and apply all the patches it specifies */
517 static UINT msi_apply_patches( MSIPACKAGE *package )
519 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
520 LPWSTR patch_list, *patches;
521 UINT i, r = ERROR_SUCCESS;
523 patch_list = msi_dup_property( package, szPatch );
525 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
527 patches = msi_split_string( patch_list, ';' );
528 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
529 r = msi_apply_patch_package( package, patches[i] );
531 msi_free( patches );
532 msi_free( patch_list );
534 return r;
537 static UINT msi_apply_transforms( MSIPACKAGE *package )
539 static const WCHAR szTransforms[] = {
540 'T','R','A','N','S','F','O','R','M','S',0 };
541 LPWSTR xform_list, *xforms;
542 UINT i, r = ERROR_SUCCESS;
544 xform_list = msi_dup_property( package, szTransforms );
545 xforms = msi_split_string( xform_list, ';' );
547 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
549 if (xforms[i][0] == ':')
550 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
551 else
552 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
555 msi_free( xforms );
556 msi_free( xform_list );
558 return r;
561 /****************************************************
562 * TOP level entry points
563 *****************************************************/
565 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
566 LPCWSTR szCommandLine )
568 UINT rc;
569 BOOL ui = FALSE;
570 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
571 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
572 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
574 MSI_SetPropertyW(package, szAction, szInstall);
576 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
578 package->script->InWhatSequence = SEQUENCE_INSTALL;
580 if (szPackagePath)
582 LPWSTR p, check, path;
584 package->PackagePath = strdupW(szPackagePath);
585 path = strdupW(szPackagePath);
586 p = strrchrW(path,'\\');
587 if (p)
589 p++;
590 *p=0;
592 else
594 msi_free(path);
595 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
596 GetCurrentDirectoryW(MAX_PATH,path);
597 strcatW(path,cszbs);
600 check = msi_dup_property( package, cszSourceDir );
601 if (!check)
602 MSI_SetPropertyW(package, cszSourceDir, path);
603 msi_free(check);
604 msi_free(path);
607 msi_parse_command_line( package, szCommandLine );
609 msi_apply_transforms( package );
610 msi_apply_patches( package );
612 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
614 package->script->InWhatSequence |= SEQUENCE_UI;
615 rc = ACTION_ProcessUISequence(package);
616 ui = TRUE;
617 if (rc == ERROR_SUCCESS)
619 package->script->InWhatSequence |= SEQUENCE_EXEC;
620 rc = ACTION_ProcessExecSequence(package,TRUE);
623 else
624 rc = ACTION_ProcessExecSequence(package,FALSE);
626 if (rc == -1)
628 /* install was halted but should be considered a success */
629 rc = ERROR_SUCCESS;
632 package->script->CurrentlyScripting= FALSE;
634 /* process the ending type action */
635 if (rc == ERROR_SUCCESS)
636 ACTION_PerformActionSequence(package,-1,ui);
637 else if (rc == ERROR_INSTALL_USEREXIT)
638 ACTION_PerformActionSequence(package,-2,ui);
639 else if (rc == ERROR_INSTALL_SUSPEND)
640 ACTION_PerformActionSequence(package,-4,ui);
641 else /* failed */
642 ACTION_PerformActionSequence(package,-3,ui);
644 /* finish up running custom actions */
645 ACTION_FinishCustomActions(package);
647 return rc;
650 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
652 UINT rc = ERROR_SUCCESS;
653 MSIRECORD * row = 0;
654 static const WCHAR ExecSeqQuery[] =
655 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
656 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
657 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
658 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
660 static const WCHAR UISeqQuery[] =
661 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
662 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
663 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
664 ' ', '=',' ','%','i',0};
666 if (UI)
667 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
668 else
669 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
671 if (row)
673 LPCWSTR action, cond;
675 TRACE("Running the actions\n");
677 /* check conditions */
678 cond = MSI_RecordGetString(row,2);
679 if (cond)
681 /* this is a hack to skip errors in the condition code */
682 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
683 goto end;
686 action = MSI_RecordGetString(row,1);
687 if (!action)
689 ERR("failed to fetch action\n");
690 rc = ERROR_FUNCTION_FAILED;
691 goto end;
694 if (UI)
695 rc = ACTION_PerformUIAction(package,action);
696 else
697 rc = ACTION_PerformAction(package,action,FALSE);
698 end:
699 msiobj_release(&row->hdr);
701 else
702 rc = ERROR_SUCCESS;
704 return rc;
707 typedef struct {
708 MSIPACKAGE* package;
709 BOOL UI;
710 } iterate_action_param;
712 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
714 iterate_action_param *iap= (iterate_action_param*)param;
715 UINT rc;
716 LPCWSTR cond, action;
718 action = MSI_RecordGetString(row,1);
719 if (!action)
721 ERR("Error is retrieving action name\n");
722 return ERROR_FUNCTION_FAILED;
725 /* check conditions */
726 cond = MSI_RecordGetString(row,2);
727 if (cond)
729 /* this is a hack to skip errors in the condition code */
730 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
732 TRACE("Skipping action: %s (condition is false)\n",
733 debugstr_w(action));
734 return ERROR_SUCCESS;
738 if (iap->UI)
739 rc = ACTION_PerformUIAction(iap->package,action);
740 else
741 rc = ACTION_PerformAction(iap->package,action,FALSE);
743 msi_dialog_check_messages( NULL );
745 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
746 rc = iap->package->CurrentInstallState;
748 if (rc == ERROR_FUNCTION_NOT_CALLED)
749 rc = ERROR_SUCCESS;
751 if (rc != ERROR_SUCCESS)
752 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
754 return rc;
757 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
759 MSIQUERY * view;
760 UINT r;
761 static const WCHAR query[] =
762 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
763 '`','%','s','`',
764 ' ','W','H','E','R','E',' ',
765 '`','S','e','q','u','e','n','c','e','`',' ',
766 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
767 '`','S','e','q','u','e','n','c','e','`',0};
768 iterate_action_param iap;
771 * FIXME: probably should be checking UILevel in the
772 * ACTION_PerformUIAction/ACTION_PerformAction
773 * rather than saving the UI level here. Those
774 * two functions can be merged too.
776 iap.package = package;
777 iap.UI = TRUE;
779 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
781 r = MSI_OpenQuery( package->db, &view, query, szTable );
782 if (r == ERROR_SUCCESS)
784 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
785 msiobj_release(&view->hdr);
788 return r;
791 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
793 MSIQUERY * view;
794 UINT rc;
795 static const WCHAR ExecSeqQuery[] =
796 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
797 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
798 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
799 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
800 'O','R','D','E','R',' ', 'B','Y',' ',
801 '`','S','e','q','u','e','n','c','e','`',0 };
802 MSIRECORD * row = 0;
803 static const WCHAR IVQuery[] =
804 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
805 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
806 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
807 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
808 ' ','\'', 'I','n','s','t','a','l','l',
809 'V','a','l','i','d','a','t','e','\'', 0};
810 INT seq = 0;
811 iterate_action_param iap;
813 iap.package = package;
814 iap.UI = FALSE;
816 if (package->script->ExecuteSequenceRun)
818 TRACE("Execute Sequence already Run\n");
819 return ERROR_SUCCESS;
822 package->script->ExecuteSequenceRun = TRUE;
824 /* get the sequence number */
825 if (UIran)
827 row = MSI_QueryGetRecord(package->db, IVQuery);
828 if( !row )
829 return ERROR_FUNCTION_FAILED;
830 seq = MSI_RecordGetInteger(row,1);
831 msiobj_release(&row->hdr);
834 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
835 if (rc == ERROR_SUCCESS)
837 TRACE("Running the actions\n");
839 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
840 msiobj_release(&view->hdr);
843 return rc;
846 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
848 MSIQUERY * view;
849 UINT rc;
850 static const WCHAR ExecSeqQuery [] =
851 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
852 '`','I','n','s','t','a','l','l',
853 'U','I','S','e','q','u','e','n','c','e','`',
854 ' ','W','H','E','R','E',' ',
855 '`','S','e','q','u','e','n','c','e','`',' ',
856 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
857 '`','S','e','q','u','e','n','c','e','`',0};
858 iterate_action_param iap;
860 iap.package = package;
861 iap.UI = TRUE;
863 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
865 if (rc == ERROR_SUCCESS)
867 TRACE("Running the actions\n");
869 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
870 msiobj_release(&view->hdr);
873 return rc;
876 /********************************************************
877 * ACTION helper functions and functions that perform the actions
878 *******************************************************/
879 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
880 UINT* rc, BOOL force )
882 BOOL ret = FALSE;
883 BOOL run = force;
884 int i;
886 if (!run && !package->script->CurrentlyScripting)
887 run = TRUE;
889 if (!run)
891 if (strcmpW(action,szInstallFinalize) == 0 ||
892 strcmpW(action,szInstallExecute) == 0 ||
893 strcmpW(action,szInstallExecuteAgain) == 0)
894 run = TRUE;
897 i = 0;
898 while (StandardActions[i].action != NULL)
900 if (strcmpW(StandardActions[i].action, action)==0)
902 if (!run)
904 ui_actioninfo(package, action, TRUE, 0);
905 *rc = schedule_action(package,INSTALL_SCRIPT,action);
906 ui_actioninfo(package, action, FALSE, *rc);
908 else
910 ui_actionstart(package, action);
911 if (StandardActions[i].handler)
913 *rc = StandardActions[i].handler(package);
915 else
917 FIXME("unhandled standard action %s\n",debugstr_w(action));
918 *rc = ERROR_SUCCESS;
921 ret = TRUE;
922 break;
924 i++;
926 return ret;
929 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
930 UINT* rc, BOOL force )
932 BOOL ret=FALSE;
933 UINT arc;
935 arc = ACTION_CustomAction(package,action, force);
937 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
939 *rc = arc;
940 ret = TRUE;
942 return ret;
946 * A lot of actions are really important even if they don't do anything
947 * explicit... Lots of properties are set at the beginning of the installation
948 * CostFinalize does a bunch of work to translate the directories and such
950 * But until I get write access to the database that is hard, so I am going to
951 * hack it to see if I can get something to run.
953 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
955 UINT rc = ERROR_SUCCESS;
956 BOOL handled;
958 TRACE("Performing action (%s)\n",debugstr_w(action));
960 handled = ACTION_HandleStandardAction(package, action, &rc, force);
962 if (!handled)
963 handled = ACTION_HandleCustomAction(package, action, &rc, force);
965 if (!handled)
967 FIXME("unhandled msi action %s\n",debugstr_w(action));
968 rc = ERROR_FUNCTION_NOT_CALLED;
971 return rc;
974 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
976 UINT rc = ERROR_SUCCESS;
977 BOOL handled = FALSE;
979 TRACE("Performing action (%s)\n",debugstr_w(action));
981 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
983 if (!handled)
984 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
986 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
987 handled = TRUE;
989 if (!handled)
991 FIXME("unhandled msi action %s\n",debugstr_w(action));
992 rc = ERROR_FUNCTION_NOT_CALLED;
995 return rc;
1000 * Actual Action Handlers
1003 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1005 MSIPACKAGE *package = (MSIPACKAGE*)param;
1006 LPCWSTR dir;
1007 LPWSTR full_path;
1008 MSIRECORD *uirow;
1009 MSIFOLDER *folder;
1011 dir = MSI_RecordGetString(row,1);
1012 if (!dir)
1014 ERR("Unable to get folder id\n");
1015 return ERROR_SUCCESS;
1018 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1019 if (!full_path)
1021 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1022 return ERROR_SUCCESS;
1025 TRACE("Folder is %s\n",debugstr_w(full_path));
1027 /* UI stuff */
1028 uirow = MSI_CreateRecord(1);
1029 MSI_RecordSetStringW(uirow,1,full_path);
1030 ui_actiondata(package,szCreateFolders,uirow);
1031 msiobj_release( &uirow->hdr );
1033 if (folder->State == 0)
1034 create_full_pathW(full_path);
1036 folder->State = 3;
1038 msi_free(full_path);
1039 return ERROR_SUCCESS;
1042 /* FIXME: probably should merge this with the above function */
1043 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1045 UINT rc = ERROR_SUCCESS;
1046 MSIFOLDER *folder;
1047 LPWSTR install_path;
1049 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1050 if (!install_path)
1051 return ERROR_FUNCTION_FAILED;
1053 /* create the path */
1054 if (folder->State == 0)
1056 create_full_pathW(install_path);
1057 folder->State = 2;
1059 msi_free(install_path);
1061 return rc;
1064 UINT msi_create_component_directories( MSIPACKAGE *package )
1066 MSICOMPONENT *comp;
1068 /* create all the folders required by the components are going to install */
1069 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1071 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1072 continue;
1073 msi_create_directory( package, comp->Directory );
1076 return ERROR_SUCCESS;
1080 * Also we cannot enable/disable components either, so for now I am just going
1081 * to do all the directories for all the components.
1083 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1085 static const WCHAR ExecSeqQuery[] =
1086 {'S','E','L','E','C','T',' ',
1087 '`','D','i','r','e','c','t','o','r','y','_','`',
1088 ' ','F','R','O','M',' ',
1089 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1090 UINT rc;
1091 MSIQUERY *view;
1093 /* create all the empty folders specified in the CreateFolder table */
1094 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1095 if (rc != ERROR_SUCCESS)
1096 return ERROR_SUCCESS;
1098 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1099 msiobj_release(&view->hdr);
1101 msi_create_component_directories( package );
1103 return rc;
1106 static MSICOMPONENT* load_component( MSIRECORD * row )
1108 MSICOMPONENT *comp;
1110 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1111 if (!comp)
1112 return comp;
1114 /* fill in the data */
1115 comp->Component = msi_dup_record_field( row, 1 );
1117 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1119 comp->ComponentId = msi_dup_record_field( row, 2 );
1120 comp->Directory = msi_dup_record_field( row, 3 );
1121 comp->Attributes = MSI_RecordGetInteger(row,4);
1122 comp->Condition = msi_dup_record_field( row, 5 );
1123 comp->KeyPath = msi_dup_record_field( row, 6 );
1125 comp->Installed = INSTALLSTATE_ABSENT;
1126 comp->Action = INSTALLSTATE_UNKNOWN;
1127 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1129 comp->Enabled = TRUE;
1131 return comp;
1134 typedef struct {
1135 MSIPACKAGE *package;
1136 MSIFEATURE *feature;
1137 } _ilfs;
1139 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1141 ComponentList *cl;
1143 cl = msi_alloc( sizeof (*cl) );
1144 if ( !cl )
1145 return ERROR_NOT_ENOUGH_MEMORY;
1146 cl->component = comp;
1147 list_add_tail( &feature->Components, &cl->entry );
1149 return ERROR_SUCCESS;
1152 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1154 _ilfs* ilfs= (_ilfs*)param;
1155 MSIPACKAGE *package = ilfs->package;
1156 MSIFEATURE *feature = ilfs->feature;
1157 MSICOMPONENT *comp;
1159 comp = load_component( row );
1160 if (!comp)
1161 return ERROR_FUNCTION_FAILED;
1163 list_add_tail( &package->components, &comp->entry );
1164 add_feature_component( feature, comp );
1166 TRACE("Loaded new component %p\n", comp);
1168 return ERROR_SUCCESS;
1171 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1173 _ilfs* ilfs= (_ilfs*)param;
1174 LPCWSTR component;
1175 DWORD rc;
1176 MSICOMPONENT *comp;
1177 MSIQUERY * view;
1178 static const WCHAR Query[] =
1179 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1180 '`','C','o','m','p','o','n','e','n','t','`',' ',
1181 'W','H','E','R','E',' ',
1182 '`','C','o','m','p','o','n','e','n','t','`',' ',
1183 '=','\'','%','s','\'',0};
1185 component = MSI_RecordGetString(row,1);
1187 /* check to see if the component is already loaded */
1188 comp = get_loaded_component( ilfs->package, component );
1189 if (comp)
1191 TRACE("Component %s already loaded\n", debugstr_w(component) );
1192 add_feature_component( ilfs->feature, comp );
1193 return ERROR_SUCCESS;
1196 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1197 if (rc != ERROR_SUCCESS)
1198 return ERROR_SUCCESS;
1200 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1201 msiobj_release( &view->hdr );
1203 return ERROR_SUCCESS;
1206 static UINT load_feature(MSIRECORD * row, LPVOID param)
1208 MSIPACKAGE* package = (MSIPACKAGE*)param;
1209 MSIFEATURE* feature;
1210 static const WCHAR Query1[] =
1211 {'S','E','L','E','C','T',' ',
1212 '`','C','o','m','p','o','n','e','n','t','_','`',
1213 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1214 'C','o','m','p','o','n','e','n','t','s','`',' ',
1215 'W','H','E','R','E',' ',
1216 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1217 MSIQUERY * view;
1218 UINT rc;
1219 _ilfs ilfs;
1221 /* fill in the data */
1223 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1224 if (!feature)
1225 return ERROR_NOT_ENOUGH_MEMORY;
1227 list_init( &feature->Components );
1229 feature->Feature = msi_dup_record_field( row, 1 );
1231 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1233 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1234 feature->Title = msi_dup_record_field( row, 3 );
1235 feature->Description = msi_dup_record_field( row, 4 );
1237 if (!MSI_RecordIsNull(row,5))
1238 feature->Display = MSI_RecordGetInteger(row,5);
1240 feature->Level= MSI_RecordGetInteger(row,6);
1241 feature->Directory = msi_dup_record_field( row, 7 );
1242 feature->Attributes = MSI_RecordGetInteger(row,8);
1244 feature->Installed = INSTALLSTATE_ABSENT;
1245 feature->Action = INSTALLSTATE_UNKNOWN;
1246 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1248 list_add_tail( &package->features, &feature->entry );
1250 /* load feature components */
1252 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1253 if (rc != ERROR_SUCCESS)
1254 return ERROR_SUCCESS;
1256 ilfs.package = package;
1257 ilfs.feature = feature;
1259 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1260 msiobj_release(&view->hdr);
1262 return ERROR_SUCCESS;
1265 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1267 if (!p)
1268 return p;
1269 p = strchrW(p, ch);
1270 if (!p)
1271 return p;
1272 *p = 0;
1273 return p+1;
1276 static UINT load_file(MSIRECORD *row, LPVOID param)
1278 MSIPACKAGE* package = (MSIPACKAGE*)param;
1279 LPCWSTR component;
1280 MSIFILE *file;
1282 /* fill in the data */
1284 file = msi_alloc_zero( sizeof (MSIFILE) );
1285 if (!file)
1286 return ERROR_NOT_ENOUGH_MEMORY;
1288 file->File = msi_dup_record_field( row, 1 );
1290 component = MSI_RecordGetString( row, 2 );
1291 file->Component = get_loaded_component( package, component );
1293 if (!file->Component)
1294 ERR("Unfound Component %s\n",debugstr_w(component));
1296 file->FileName = msi_dup_record_field( row, 3 );
1297 reduce_to_longfilename( file->FileName );
1299 file->ShortName = msi_dup_record_field( row, 3 );
1300 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1302 file->FileSize = MSI_RecordGetInteger( row, 4 );
1303 file->Version = msi_dup_record_field( row, 5 );
1304 file->Language = msi_dup_record_field( row, 6 );
1305 file->Attributes = MSI_RecordGetInteger( row, 7 );
1306 file->Sequence = MSI_RecordGetInteger( row, 8 );
1308 file->state = msifs_invalid;
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1312 list_add_tail( &package->files, &file->entry );
1314 return ERROR_SUCCESS;
1317 static UINT load_all_files(MSIPACKAGE *package)
1319 MSIQUERY * view;
1320 UINT rc;
1321 static const WCHAR Query[] =
1322 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1323 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1324 '`','S','e','q','u','e','n','c','e','`', 0};
1326 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1327 if (rc != ERROR_SUCCESS)
1328 return ERROR_SUCCESS;
1330 rc = MSI_IterateRecords(view, NULL, load_file, package);
1331 msiobj_release(&view->hdr);
1333 return ERROR_SUCCESS;
1338 * I am not doing any of the costing functionality yet.
1339 * Mostly looking at doing the Component and Feature loading
1341 * The native MSI does A LOT of modification to tables here. Mostly adding
1342 * a lot of temporary columns to the Feature and Component tables.
1344 * note: Native msi also tracks the short filename. But I am only going to
1345 * track the long ones. Also looking at this directory table
1346 * it appears that the directory table does not get the parents
1347 * resolved base on property only based on their entries in the
1348 * directory table.
1350 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1352 MSIQUERY * view;
1353 UINT rc;
1354 static const WCHAR Query_all[] =
1355 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1356 '`','F','e','a','t','u','r','e','`',0};
1357 static const WCHAR szCosting[] =
1358 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1359 static const WCHAR szZero[] = { '0', 0 };
1361 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1362 return ERROR_SUCCESS;
1364 MSI_SetPropertyW(package, szCosting, szZero);
1365 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1367 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1368 if (rc != ERROR_SUCCESS)
1369 return rc;
1371 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1372 msiobj_release(&view->hdr);
1374 load_all_files(package);
1376 return ERROR_SUCCESS;
1379 static UINT execute_script(MSIPACKAGE *package, UINT script )
1381 int i;
1382 UINT rc = ERROR_SUCCESS;
1384 TRACE("Executing Script %i\n",script);
1386 if (!package->script)
1388 ERR("no script!\n");
1389 return ERROR_FUNCTION_FAILED;
1392 for (i = 0; i < package->script->ActionCount[script]; i++)
1394 LPWSTR action;
1395 action = package->script->Actions[script][i];
1396 ui_actionstart(package, action);
1397 TRACE("Executing Action (%s)\n",debugstr_w(action));
1398 rc = ACTION_PerformAction(package, action, TRUE);
1399 msi_free(package->script->Actions[script][i]);
1400 if (rc != ERROR_SUCCESS)
1401 break;
1403 msi_free(package->script->Actions[script]);
1405 package->script->ActionCount[script] = 0;
1406 package->script->Actions[script] = NULL;
1407 return rc;
1410 static UINT ACTION_FileCost(MSIPACKAGE *package)
1412 return ERROR_SUCCESS;
1415 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1417 static const WCHAR Query[] =
1418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1419 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1420 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1421 ' ','=',' ','\'','%','s','\'',
1423 static const WCHAR szDot[] = { '.',0 };
1424 static WCHAR szEmpty[] = { 0 };
1425 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1426 LPCWSTR parent;
1427 MSIRECORD *row;
1428 MSIFOLDER *folder;
1430 TRACE("Looking for dir %s\n",debugstr_w(dir));
1432 folder = get_loaded_folder( package, dir );
1433 if (folder)
1434 return folder;
1436 TRACE("Working to load %s\n",debugstr_w(dir));
1438 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1439 if (!folder)
1440 return NULL;
1442 folder->Directory = strdupW(dir);
1444 row = MSI_QueryGetRecord(package->db, Query, dir);
1445 if (!row)
1446 return NULL;
1448 p = msi_dup_record_field(row, 3);
1450 /* split src and target dir */
1451 tgt_short = p;
1452 src_short = folder_split_path( p, ':' );
1454 /* split the long and short paths */
1455 tgt_long = folder_split_path( tgt_short, '|' );
1456 src_long = folder_split_path( src_short, '|' );
1458 /* check for no-op dirs */
1459 if (!lstrcmpW(szDot, tgt_short))
1460 tgt_short = szEmpty;
1461 if (!lstrcmpW(szDot, src_short))
1462 src_short = szEmpty;
1464 if (!tgt_long)
1465 tgt_long = tgt_short;
1467 if (!src_short) {
1468 src_short = tgt_short;
1469 src_long = tgt_long;
1472 if (!src_long)
1473 src_long = src_short;
1475 /* FIXME: use the target short path too */
1476 folder->TargetDefault = strdupW(tgt_long);
1477 folder->SourceShortPath = strdupW(src_short);
1478 folder->SourceLongPath = strdupW(src_long);
1479 msi_free(p);
1481 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1482 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1483 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1485 parent = MSI_RecordGetString(row, 2);
1486 if (parent)
1488 folder->Parent = load_folder( package, parent );
1489 if ( folder->Parent )
1490 TRACE("loaded parent %p %s\n", folder->Parent,
1491 debugstr_w(folder->Parent->Directory));
1492 else
1493 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1496 folder->Property = msi_dup_property( package, dir );
1498 msiobj_release(&row->hdr);
1500 list_add_tail( &package->folders, &folder->entry );
1502 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1504 return folder;
1507 /* scan for and update current install states */
1508 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1510 MSICOMPONENT *comp;
1511 MSIFEATURE *feature;
1513 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1515 INSTALLSTATE res;
1516 res = MsiGetComponentPathW( package->ProductCode,
1517 comp->ComponentId, NULL, NULL);
1518 if (res < 0)
1519 res = INSTALLSTATE_ABSENT;
1520 comp->Installed = res;
1523 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1525 ComponentList *cl;
1526 INSTALLSTATE res = -10;
1528 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1530 comp= cl->component;
1532 if (res == -10)
1533 res = comp->Installed;
1534 else
1536 if (res == comp->Installed)
1537 continue;
1539 if (res != comp->Installed)
1540 res = INSTALLSTATE_INCOMPLETE;
1543 feature->Installed = res;
1547 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1548 INSTALLSTATE state)
1550 static const WCHAR all[]={'A','L','L',0};
1551 LPWSTR override;
1552 MSIFEATURE *feature;
1554 override = msi_dup_property( package, property );
1555 if (!override)
1556 return FALSE;
1558 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1560 if (strcmpiW(override,all)==0)
1562 feature->ActionRequest= state;
1563 feature->Action = state;
1565 else
1567 LPWSTR ptr = override;
1568 LPWSTR ptr2 = strchrW(override,',');
1570 while (ptr)
1572 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1573 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1575 feature->ActionRequest= state;
1576 feature->Action = state;
1577 break;
1579 if (ptr2)
1581 ptr=ptr2+1;
1582 ptr2 = strchrW(ptr,',');
1584 else
1585 break;
1589 msi_free(override);
1591 return TRUE;
1594 static UINT SetFeatureStates(MSIPACKAGE *package)
1596 int install_level;
1597 static const WCHAR szlevel[] =
1598 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1599 static const WCHAR szAddLocal[] =
1600 {'A','D','D','L','O','C','A','L',0};
1601 static const WCHAR szRemove[] =
1602 {'R','E','M','O','V','E',0};
1603 static const WCHAR szReinstall[] =
1604 {'R','E','I','N','S','T','A','L','L',0};
1605 BOOL override = FALSE;
1606 MSICOMPONENT* component;
1607 MSIFEATURE *feature;
1610 /* I do not know if this is where it should happen.. but */
1612 TRACE("Checking Install Level\n");
1614 install_level = msi_get_property_int( package, szlevel, 1 );
1616 /* ok hereis the _real_ rub
1617 * all these activation/deactivation things happen in order and things
1618 * later on the list override things earlier on the list.
1619 * 1) INSTALLLEVEL processing
1620 * 2) ADDLOCAL
1621 * 3) REMOVE
1622 * 4) ADDSOURCE
1623 * 5) ADDDEFAULT
1624 * 6) REINSTALL
1625 * 7) COMPADDLOCAL
1626 * 8) COMPADDSOURCE
1627 * 9) FILEADDLOCAL
1628 * 10) FILEADDSOURCE
1629 * 11) FILEADDDEFAULT
1630 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1631 * ignored for all the features. seems strange, especially since it is not
1632 * documented anywhere, but it is how it works.
1634 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1635 * REMOVE are the big ones, since we don't handle administrative installs
1636 * yet anyway.
1638 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1639 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1640 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1642 if (!override)
1644 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1646 BOOL feature_state = ((feature->Level > 0) &&
1647 (feature->Level <= install_level));
1649 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1651 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1653 feature->ActionRequest = INSTALLSTATE_SOURCE;
1654 feature->Action = INSTALLSTATE_SOURCE;
1656 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1658 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1659 feature->Action = INSTALLSTATE_ADVERTISED;
1661 else
1663 feature->ActionRequest = INSTALLSTATE_LOCAL;
1664 feature->Action = INSTALLSTATE_LOCAL;
1669 else
1671 /* set the Preselected Property */
1672 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1673 static const WCHAR szOne[] = { '1', 0 };
1675 MSI_SetPropertyW(package,szPreselected,szOne);
1679 * now we want to enable or disable components base on feature
1682 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1684 ComponentList *cl;
1686 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1687 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1688 feature->ActionRequest);
1690 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1692 component = cl->component;
1694 if (!component->Enabled)
1696 component->Action = INSTALLSTATE_UNKNOWN;
1697 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1699 else
1701 if (feature->Action == INSTALLSTATE_LOCAL)
1703 component->Action = INSTALLSTATE_LOCAL;
1704 component->ActionRequest = INSTALLSTATE_LOCAL;
1706 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1708 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1709 (component->Action == INSTALLSTATE_ABSENT) ||
1710 (component->Action == INSTALLSTATE_ADVERTISED))
1713 component->Action = INSTALLSTATE_SOURCE;
1714 component->ActionRequest = INSTALLSTATE_SOURCE;
1717 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1719 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1720 (component->Action == INSTALLSTATE_ABSENT))
1723 component->Action = INSTALLSTATE_ADVERTISED;
1724 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1727 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1729 if (component->Action == INSTALLSTATE_UNKNOWN)
1731 component->Action = INSTALLSTATE_ABSENT;
1732 component->ActionRequest = INSTALLSTATE_ABSENT;
1739 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1741 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1742 debugstr_w(component->Component), component->Installed,
1743 component->Action, component->ActionRequest);
1747 return ERROR_SUCCESS;
1750 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1752 MSIPACKAGE *package = (MSIPACKAGE*)param;
1753 LPCWSTR name;
1754 LPWSTR path;
1756 name = MSI_RecordGetString(row,1);
1758 /* This helper function now does ALL the work */
1759 TRACE("Dir %s ...\n",debugstr_w(name));
1760 load_folder(package,name);
1761 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1762 TRACE("resolves to %s\n",debugstr_w(path));
1763 msi_free(path);
1765 return ERROR_SUCCESS;
1768 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1770 MSIPACKAGE *package = (MSIPACKAGE*)param;
1771 LPCWSTR name;
1772 MSIFEATURE *feature;
1774 name = MSI_RecordGetString( row, 1 );
1776 feature = get_loaded_feature( package, name );
1777 if (!feature)
1778 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1779 else
1781 LPCWSTR Condition;
1782 Condition = MSI_RecordGetString(row,3);
1784 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1786 int level = MSI_RecordGetInteger(row,2);
1787 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1788 feature->Level = level;
1791 return ERROR_SUCCESS;
1796 * A lot is done in this function aside from just the costing.
1797 * The costing needs to be implemented at some point but for now I am going
1798 * to focus on the directory building
1801 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1803 static const WCHAR ExecSeqQuery[] =
1804 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1805 '`','D','i','r','e','c','t','o','r','y','`',0};
1806 static const WCHAR ConditionQuery[] =
1807 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1808 '`','C','o','n','d','i','t','i','o','n','`',0};
1809 static const WCHAR szCosting[] =
1810 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1811 static const WCHAR szlevel[] =
1812 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1813 static const WCHAR szOne[] = { '1', 0 };
1814 MSICOMPONENT *comp;
1815 MSIFILE *file;
1816 UINT rc;
1817 MSIQUERY * view;
1818 LPWSTR level;
1820 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1821 return ERROR_SUCCESS;
1823 TRACE("Building Directory properties\n");
1825 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1826 if (rc == ERROR_SUCCESS)
1828 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1829 package);
1830 msiobj_release(&view->hdr);
1833 TRACE("File calculations\n");
1835 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1837 MSICOMPONENT* comp = file->Component;
1838 LPWSTR p;
1840 if (!comp)
1841 continue;
1843 /* calculate target */
1844 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1846 msi_free(file->TargetPath);
1848 TRACE("file %s is named %s\n",
1849 debugstr_w(file->File),debugstr_w(file->FileName));
1851 file->TargetPath = build_directory_name(2, p, file->FileName);
1853 msi_free(p);
1855 TRACE("file %s resolves to %s\n",
1856 debugstr_w(file->File),debugstr_w(file->TargetPath));
1858 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1860 file->state = msifs_missing;
1861 comp->Cost += file->FileSize;
1862 continue;
1865 if (file->Version)
1867 DWORD handle;
1868 DWORD versize;
1869 UINT sz;
1870 LPVOID version;
1871 static WCHAR name[] = {'\\',0};
1872 static const WCHAR name_fmt[] =
1873 {'%','u','.','%','u','.','%','u','.','%','u',0};
1874 WCHAR filever[0x100];
1875 VS_FIXEDFILEINFO *lpVer;
1877 TRACE("Version comparison..\n");
1878 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1879 version = msi_alloc(versize);
1880 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1882 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1884 sprintfW(filever,name_fmt,
1885 HIWORD(lpVer->dwFileVersionMS),
1886 LOWORD(lpVer->dwFileVersionMS),
1887 HIWORD(lpVer->dwFileVersionLS),
1888 LOWORD(lpVer->dwFileVersionLS));
1890 TRACE("new %s old %s\n", debugstr_w(file->Version),
1891 debugstr_w(filever));
1892 if (strcmpiW(filever,file->Version)<0)
1894 file->state = msifs_overwrite;
1895 /* FIXME: cost should be diff in size */
1896 comp->Cost += file->FileSize;
1898 else
1899 file->state = msifs_present;
1900 msi_free(version);
1902 else
1903 file->state = msifs_present;
1906 TRACE("Evaluating Condition Table\n");
1908 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1909 if (rc == ERROR_SUCCESS)
1911 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1912 package);
1913 msiobj_release(&view->hdr);
1916 TRACE("Enabling or Disabling Components\n");
1917 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1919 if (comp->Condition)
1921 if (MSI_EvaluateConditionW(package,
1922 comp->Condition) == MSICONDITION_FALSE)
1924 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1925 comp->Enabled = FALSE;
1930 MSI_SetPropertyW(package,szCosting,szOne);
1931 /* set default run level if not set */
1932 level = msi_dup_property( package, szlevel );
1933 if (!level)
1934 MSI_SetPropertyW(package,szlevel, szOne);
1935 msi_free(level);
1937 ACTION_UpdateInstallStates(package);
1939 return SetFeatureStates(package);
1942 /* OK this value is "interpreted" and then formatted based on the
1943 first few characters */
1944 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1945 DWORD *size)
1947 LPSTR data = NULL;
1948 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1950 if (value[1]=='x')
1952 LPWSTR ptr;
1953 CHAR byte[5];
1954 LPWSTR deformated = NULL;
1955 int count;
1957 deformat_string(package, &value[2], &deformated);
1959 /* binary value type */
1960 ptr = deformated;
1961 *type = REG_BINARY;
1962 if (strlenW(ptr)%2)
1963 *size = (strlenW(ptr)/2)+1;
1964 else
1965 *size = strlenW(ptr)/2;
1967 data = msi_alloc(*size);
1969 byte[0] = '0';
1970 byte[1] = 'x';
1971 byte[4] = 0;
1972 count = 0;
1973 /* if uneven pad with a zero in front */
1974 if (strlenW(ptr)%2)
1976 byte[2]= '0';
1977 byte[3]= *ptr;
1978 ptr++;
1979 data[count] = (BYTE)strtol(byte,NULL,0);
1980 count ++;
1981 TRACE("Uneven byte count\n");
1983 while (*ptr)
1985 byte[2]= *ptr;
1986 ptr++;
1987 byte[3]= *ptr;
1988 ptr++;
1989 data[count] = (BYTE)strtol(byte,NULL,0);
1990 count ++;
1992 msi_free(deformated);
1994 TRACE("Data %li bytes(%i)\n",*size,count);
1996 else
1998 LPWSTR deformated;
1999 LPWSTR p;
2000 DWORD d = 0;
2001 deformat_string(package, &value[1], &deformated);
2003 *type=REG_DWORD;
2004 *size = sizeof(DWORD);
2005 data = msi_alloc(*size);
2006 p = deformated;
2007 if (*p == '-')
2008 p++;
2009 while (*p)
2011 if ( (*p < '0') || (*p > '9') )
2012 break;
2013 d *= 10;
2014 d += (*p - '0');
2015 p++;
2017 if (deformated[0] == '-')
2018 d = -d;
2019 *(LPDWORD)data = d;
2020 TRACE("DWORD %li\n",*(LPDWORD)data);
2022 msi_free(deformated);
2025 else
2027 static const WCHAR szMulti[] = {'[','~',']',0};
2028 LPCWSTR ptr;
2029 *type=REG_SZ;
2031 if (value[0]=='#')
2033 if (value[1]=='%')
2035 ptr = &value[2];
2036 *type=REG_EXPAND_SZ;
2038 else
2039 ptr = &value[1];
2041 else
2042 ptr=value;
2044 if (strstrW(value,szMulti))
2045 *type = REG_MULTI_SZ;
2047 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2049 return data;
2052 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2054 MSIPACKAGE *package = (MSIPACKAGE*)param;
2055 static const WCHAR szHCR[] =
2056 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2057 'R','O','O','T','\\',0};
2058 static const WCHAR szHCU[] =
2059 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2060 'U','S','E','R','\\',0};
2061 static const WCHAR szHLM[] =
2062 {'H','K','E','Y','_','L','O','C','A','L','_',
2063 'M','A','C','H','I','N','E','\\',0};
2064 static const WCHAR szHU[] =
2065 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2067 LPSTR value_data = NULL;
2068 HKEY root_key, hkey;
2069 DWORD type,size;
2070 LPWSTR deformated;
2071 LPCWSTR szRoot, component, name, key, value;
2072 MSICOMPONENT *comp;
2073 MSIRECORD * uirow;
2074 LPWSTR uikey;
2075 INT root;
2076 BOOL check_first = FALSE;
2077 UINT rc;
2079 ui_progress(package,2,0,0,0);
2081 value = NULL;
2082 key = NULL;
2083 uikey = NULL;
2084 name = NULL;
2086 component = MSI_RecordGetString(row, 6);
2087 comp = get_loaded_component(package,component);
2088 if (!comp)
2089 return ERROR_SUCCESS;
2091 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2093 TRACE("Skipping write due to disabled component %s\n",
2094 debugstr_w(component));
2096 comp->Action = comp->Installed;
2098 return ERROR_SUCCESS;
2101 comp->Action = INSTALLSTATE_LOCAL;
2103 name = MSI_RecordGetString(row, 4);
2104 if( MSI_RecordIsNull(row,5) && name )
2106 /* null values can have special meanings */
2107 if (name[0]=='-' && name[1] == 0)
2108 return ERROR_SUCCESS;
2109 else if ((name[0]=='+' && name[1] == 0) ||
2110 (name[0] == '*' && name[1] == 0))
2111 name = NULL;
2112 check_first = TRUE;
2115 root = MSI_RecordGetInteger(row,2);
2116 key = MSI_RecordGetString(row, 3);
2118 /* get the root key */
2119 switch (root)
2121 case -1:
2123 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2124 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2125 if (all_users && all_users[0] == '1')
2127 root_key = HKEY_LOCAL_MACHINE;
2128 szRoot = szHLM;
2130 else
2132 root_key = HKEY_CURRENT_USER;
2133 szRoot = szHCU;
2135 msi_free(all_users);
2137 break;
2138 case 0: root_key = HKEY_CLASSES_ROOT;
2139 szRoot = szHCR;
2140 break;
2141 case 1: root_key = HKEY_CURRENT_USER;
2142 szRoot = szHCU;
2143 break;
2144 case 2: root_key = HKEY_LOCAL_MACHINE;
2145 szRoot = szHLM;
2146 break;
2147 case 3: root_key = HKEY_USERS;
2148 szRoot = szHU;
2149 break;
2150 default:
2151 ERR("Unknown root %i\n",root);
2152 root_key=NULL;
2153 szRoot = NULL;
2154 break;
2156 if (!root_key)
2157 return ERROR_SUCCESS;
2159 deformat_string(package, key , &deformated);
2160 size = strlenW(deformated) + strlenW(szRoot) + 1;
2161 uikey = msi_alloc(size*sizeof(WCHAR));
2162 strcpyW(uikey,szRoot);
2163 strcatW(uikey,deformated);
2165 if (RegCreateKeyW( root_key, deformated, &hkey))
2167 ERR("Could not create key %s\n",debugstr_w(deformated));
2168 msi_free(deformated);
2169 msi_free(uikey);
2170 return ERROR_SUCCESS;
2172 msi_free(deformated);
2174 value = MSI_RecordGetString(row,5);
2175 if (value)
2176 value_data = parse_value(package, value, &type, &size);
2177 else
2179 static const WCHAR szEmpty[] = {0};
2180 value_data = (LPSTR)strdupW(szEmpty);
2181 size = 0;
2182 type = REG_SZ;
2185 deformat_string(package, name, &deformated);
2187 /* get the double nulls to terminate SZ_MULTI */
2188 if (type == REG_MULTI_SZ)
2189 size +=sizeof(WCHAR);
2191 if (!check_first)
2193 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2194 debugstr_w(uikey));
2195 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2197 else
2199 DWORD sz = 0;
2200 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2201 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2203 TRACE("value %s of %s checked already exists\n",
2204 debugstr_w(deformated), debugstr_w(uikey));
2206 else
2208 TRACE("Checked and setting value %s of %s\n",
2209 debugstr_w(deformated), debugstr_w(uikey));
2210 if (deformated || size)
2211 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2214 RegCloseKey(hkey);
2216 uirow = MSI_CreateRecord(3);
2217 MSI_RecordSetStringW(uirow,2,deformated);
2218 MSI_RecordSetStringW(uirow,1,uikey);
2220 if (type == REG_SZ)
2221 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2222 else
2223 MSI_RecordSetStringW(uirow,3,value);
2225 ui_actiondata(package,szWriteRegistryValues,uirow);
2226 msiobj_release( &uirow->hdr );
2228 msi_free(value_data);
2229 msi_free(deformated);
2230 msi_free(uikey);
2232 return ERROR_SUCCESS;
2235 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2237 UINT rc;
2238 MSIQUERY * view;
2239 static const WCHAR ExecSeqQuery[] =
2240 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2241 '`','R','e','g','i','s','t','r','y','`',0 };
2243 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2244 if (rc != ERROR_SUCCESS)
2245 return ERROR_SUCCESS;
2247 /* increment progress bar each time action data is sent */
2248 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2250 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2252 msiobj_release(&view->hdr);
2253 return rc;
2256 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2258 package->script->CurrentlyScripting = TRUE;
2260 return ERROR_SUCCESS;
2264 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2266 MSICOMPONENT *comp;
2267 DWORD progress = 0;
2268 DWORD total = 0;
2269 static const WCHAR q1[]=
2270 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2271 '`','R','e','g','i','s','t','r','y','`',0};
2272 UINT rc;
2273 MSIQUERY * view;
2274 MSIFEATURE *feature;
2275 MSIFILE *file;
2277 TRACE("InstallValidate\n");
2279 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2280 if (rc == ERROR_SUCCESS)
2282 MSI_IterateRecords( view, &progress, NULL, package );
2283 msiobj_release( &view->hdr );
2284 total += progress * REG_PROGRESS_VALUE;
2287 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2288 total += COMPONENT_PROGRESS_VALUE;
2290 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2291 total += file->FileSize;
2293 ui_progress(package,0,total,0,0);
2295 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2297 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2298 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2299 feature->ActionRequest);
2302 return ERROR_SUCCESS;
2305 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2307 MSIPACKAGE* package = (MSIPACKAGE*)param;
2308 LPCWSTR cond = NULL;
2309 LPCWSTR message = NULL;
2310 static const WCHAR title[]=
2311 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2313 cond = MSI_RecordGetString(row,1);
2315 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2317 LPWSTR deformated;
2318 message = MSI_RecordGetString(row,2);
2319 deformat_string(package,message,&deformated);
2320 MessageBoxW(NULL,deformated,title,MB_OK);
2321 msi_free(deformated);
2322 return ERROR_FUNCTION_FAILED;
2325 return ERROR_SUCCESS;
2328 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2330 UINT rc;
2331 MSIQUERY * view = NULL;
2332 static const WCHAR ExecSeqQuery[] =
2333 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2334 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2336 TRACE("Checking launch conditions\n");
2338 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2339 if (rc != ERROR_SUCCESS)
2340 return ERROR_SUCCESS;
2342 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2343 msiobj_release(&view->hdr);
2345 return rc;
2348 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2351 if (!cmp->KeyPath)
2352 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2354 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2356 MSIRECORD * row = 0;
2357 UINT root,len;
2358 LPWSTR deformated,buffer,deformated_name;
2359 LPCWSTR key,name;
2360 static const WCHAR ExecSeqQuery[] =
2361 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2362 '`','R','e','g','i','s','t','r','y','`',' ',
2363 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2364 ' ','=',' ' ,'\'','%','s','\'',0 };
2365 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2366 static const WCHAR fmt2[]=
2367 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2369 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2370 if (!row)
2371 return NULL;
2373 root = MSI_RecordGetInteger(row,2);
2374 key = MSI_RecordGetString(row, 3);
2375 name = MSI_RecordGetString(row, 4);
2376 deformat_string(package, key , &deformated);
2377 deformat_string(package, name, &deformated_name);
2379 len = strlenW(deformated) + 6;
2380 if (deformated_name)
2381 len+=strlenW(deformated_name);
2383 buffer = msi_alloc( len *sizeof(WCHAR));
2385 if (deformated_name)
2386 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2387 else
2388 sprintfW(buffer,fmt,root,deformated);
2390 msi_free(deformated);
2391 msi_free(deformated_name);
2392 msiobj_release(&row->hdr);
2394 return buffer;
2396 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2398 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2399 return NULL;
2401 else
2403 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2405 if (file)
2406 return strdupW( file->TargetPath );
2408 return NULL;
2411 static HKEY openSharedDLLsKey(void)
2413 HKEY hkey=0;
2414 static const WCHAR path[] =
2415 {'S','o','f','t','w','a','r','e','\\',
2416 'M','i','c','r','o','s','o','f','t','\\',
2417 'W','i','n','d','o','w','s','\\',
2418 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2419 'S','h','a','r','e','d','D','L','L','s',0};
2421 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2422 return hkey;
2425 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2427 HKEY hkey;
2428 DWORD count=0;
2429 DWORD type;
2430 DWORD sz = sizeof(count);
2431 DWORD rc;
2433 hkey = openSharedDLLsKey();
2434 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2435 if (rc != ERROR_SUCCESS)
2436 count = 0;
2437 RegCloseKey(hkey);
2438 return count;
2441 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2443 HKEY hkey;
2445 hkey = openSharedDLLsKey();
2446 if (count > 0)
2447 msi_reg_set_val_dword( hkey, path, count );
2448 else
2449 RegDeleteValueW(hkey,path);
2450 RegCloseKey(hkey);
2451 return count;
2455 * Return TRUE if the count should be written out and FALSE if not
2457 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2459 MSIFEATURE *feature;
2460 INT count = 0;
2461 BOOL write = FALSE;
2463 /* only refcount DLLs */
2464 if (comp->KeyPath == NULL ||
2465 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2466 comp->Attributes & msidbComponentAttributesODBCDataSource)
2467 write = FALSE;
2468 else
2470 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2471 write = (count > 0);
2473 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2474 write = TRUE;
2477 /* increment counts */
2478 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2480 ComponentList *cl;
2482 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2483 continue;
2485 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2487 if ( cl->component == comp )
2488 count++;
2492 /* decrement counts */
2493 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2495 ComponentList *cl;
2497 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2498 continue;
2500 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2502 if ( cl->component == comp )
2503 count--;
2507 /* ref count all the files in the component */
2508 if (write)
2510 MSIFILE *file;
2512 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2514 if (file->Component == comp)
2515 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2519 /* add a count for permenent */
2520 if (comp->Attributes & msidbComponentAttributesPermanent)
2521 count ++;
2523 comp->RefCount = count;
2525 if (write)
2526 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2530 * Ok further analysis makes me think that this work is
2531 * actually done in the PublishComponents and PublishFeatures
2532 * step, and not here. It appears like the keypath and all that is
2533 * resolved in this step, however actually written in the Publish steps.
2534 * But we will leave it here for now because it is unclear
2536 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2538 WCHAR squished_pc[GUID_SIZE];
2539 WCHAR squished_cc[GUID_SIZE];
2540 UINT rc;
2541 MSICOMPONENT *comp;
2542 HKEY hkey=0,hkey2=0;
2544 /* writes the Component and Features values to the registry */
2546 rc = MSIREG_OpenComponents(&hkey);
2547 if (rc != ERROR_SUCCESS)
2548 return rc;
2550 squash_guid(package->ProductCode,squished_pc);
2551 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2553 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2555 MSIRECORD * uirow;
2557 ui_progress(package,2,0,0,0);
2558 if (!comp->ComponentId)
2559 continue;
2561 squash_guid(comp->ComponentId,squished_cc);
2563 msi_free(comp->FullKeypath);
2564 comp->FullKeypath = resolve_keypath( package, comp );
2566 /* do the refcounting */
2567 ACTION_RefCountComponent( package, comp );
2569 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2570 debugstr_w(comp->Component),
2571 debugstr_w(squished_cc),
2572 debugstr_w(comp->FullKeypath),
2573 comp->RefCount);
2575 * Write the keypath out if the component is to be registered
2576 * and delete the key if the component is to be deregistered
2578 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2580 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2581 if (rc != ERROR_SUCCESS)
2582 continue;
2584 if (!comp->FullKeypath)
2585 continue;
2587 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2589 if (comp->Attributes & msidbComponentAttributesPermanent)
2591 static const WCHAR szPermKey[] =
2592 { '0','0','0','0','0','0','0','0','0','0','0','0',
2593 '0','0','0','0','0','0','0','0','0','0','0','0',
2594 '0','0','0','0','0','0','0','0',0 };
2596 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2599 RegCloseKey(hkey2);
2601 /* UI stuff */
2602 uirow = MSI_CreateRecord(3);
2603 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2604 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2605 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2606 ui_actiondata(package,szProcessComponents,uirow);
2607 msiobj_release( &uirow->hdr );
2609 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2611 DWORD res;
2613 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2614 if (rc != ERROR_SUCCESS)
2615 continue;
2617 RegDeleteValueW(hkey2,squished_pc);
2619 /* if the key is empty delete it */
2620 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2621 RegCloseKey(hkey2);
2622 if (res == ERROR_NO_MORE_ITEMS)
2623 RegDeleteKeyW(hkey,squished_cc);
2625 /* UI stuff */
2626 uirow = MSI_CreateRecord(2);
2627 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2628 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2629 ui_actiondata(package,szProcessComponents,uirow);
2630 msiobj_release( &uirow->hdr );
2633 RegCloseKey(hkey);
2634 return rc;
2637 typedef struct {
2638 CLSID clsid;
2639 LPWSTR source;
2641 LPWSTR path;
2642 ITypeLib *ptLib;
2643 } typelib_struct;
2645 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2646 LPWSTR lpszName, LONG_PTR lParam)
2648 TLIBATTR *attr;
2649 typelib_struct *tl_struct = (typelib_struct*) lParam;
2650 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2651 int sz;
2652 HRESULT res;
2654 if (!IS_INTRESOURCE(lpszName))
2656 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2657 return TRUE;
2660 sz = strlenW(tl_struct->source)+4;
2661 sz *= sizeof(WCHAR);
2663 if ((INT_PTR)lpszName == 1)
2664 tl_struct->path = strdupW(tl_struct->source);
2665 else
2667 tl_struct->path = msi_alloc(sz);
2668 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2671 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2672 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2673 if (!SUCCEEDED(res))
2675 msi_free(tl_struct->path);
2676 tl_struct->path = NULL;
2678 return TRUE;
2681 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2682 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2684 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2685 return FALSE;
2688 msi_free(tl_struct->path);
2689 tl_struct->path = NULL;
2691 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2692 ITypeLib_Release(tl_struct->ptLib);
2694 return TRUE;
2697 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2699 MSIPACKAGE* package = (MSIPACKAGE*)param;
2700 LPCWSTR component;
2701 MSICOMPONENT *comp;
2702 MSIFILE *file;
2703 typelib_struct tl_struct;
2704 HMODULE module;
2705 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2707 component = MSI_RecordGetString(row,3);
2708 comp = get_loaded_component(package,component);
2709 if (!comp)
2710 return ERROR_SUCCESS;
2712 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2714 TRACE("Skipping typelib reg due to disabled component\n");
2716 comp->Action = comp->Installed;
2718 return ERROR_SUCCESS;
2721 comp->Action = INSTALLSTATE_LOCAL;
2723 file = get_loaded_file( package, comp->KeyPath );
2724 if (!file)
2725 return ERROR_SUCCESS;
2727 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2728 if (module)
2730 LPCWSTR guid;
2731 guid = MSI_RecordGetString(row,1);
2732 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2733 tl_struct.source = strdupW( file->TargetPath );
2734 tl_struct.path = NULL;
2736 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2737 (LONG_PTR)&tl_struct);
2739 if (tl_struct.path)
2741 LPWSTR help = NULL;
2742 LPCWSTR helpid;
2743 HRESULT res;
2745 helpid = MSI_RecordGetString(row,6);
2747 if (helpid)
2748 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2749 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2750 msi_free(help);
2752 if (!SUCCEEDED(res))
2753 ERR("Failed to register type library %s\n",
2754 debugstr_w(tl_struct.path));
2755 else
2757 ui_actiondata(package,szRegisterTypeLibraries,row);
2759 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2762 ITypeLib_Release(tl_struct.ptLib);
2763 msi_free(tl_struct.path);
2765 else
2766 ERR("Failed to load type library %s\n",
2767 debugstr_w(tl_struct.source));
2769 FreeLibrary(module);
2770 msi_free(tl_struct.source);
2772 else
2773 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2775 return ERROR_SUCCESS;
2778 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2781 * OK this is a bit confusing.. I am given a _Component key and I believe
2782 * that the file that is being registered as a type library is the "key file
2783 * of that component" which I interpret to mean "The file in the KeyPath of
2784 * that component".
2786 UINT rc;
2787 MSIQUERY * view;
2788 static const WCHAR Query[] =
2789 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2790 '`','T','y','p','e','L','i','b','`',0};
2792 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2793 if (rc != ERROR_SUCCESS)
2794 return ERROR_SUCCESS;
2796 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2797 msiobj_release(&view->hdr);
2798 return rc;
2801 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2803 MSIPACKAGE *package = (MSIPACKAGE*)param;
2804 LPWSTR target_file, target_folder, filename;
2805 LPCWSTR buffer, extension;
2806 MSICOMPONENT *comp;
2807 static const WCHAR szlnk[]={'.','l','n','k',0};
2808 IShellLinkW *sl = NULL;
2809 IPersistFile *pf = NULL;
2810 HRESULT res;
2812 buffer = MSI_RecordGetString(row,4);
2813 comp = get_loaded_component(package,buffer);
2814 if (!comp)
2815 return ERROR_SUCCESS;
2817 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2819 TRACE("Skipping shortcut creation due to disabled component\n");
2821 comp->Action = comp->Installed;
2823 return ERROR_SUCCESS;
2826 comp->Action = INSTALLSTATE_LOCAL;
2828 ui_actiondata(package,szCreateShortcuts,row);
2830 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2831 &IID_IShellLinkW, (LPVOID *) &sl );
2833 if (FAILED( res ))
2835 ERR("CLSID_ShellLink not available\n");
2836 goto err;
2839 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2840 if (FAILED( res ))
2842 ERR("QueryInterface(IID_IPersistFile) failed\n");
2843 goto err;
2846 buffer = MSI_RecordGetString(row,2);
2847 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2849 /* may be needed because of a bug somehwere else */
2850 create_full_pathW(target_folder);
2852 filename = msi_dup_record_field( row, 3 );
2853 reduce_to_longfilename(filename);
2855 extension = strchrW(filename,'.');
2856 if (!extension || strcmpiW(extension,szlnk))
2858 int len = strlenW(filename);
2859 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2860 memcpy(filename + len, szlnk, sizeof(szlnk));
2862 target_file = build_directory_name(2, target_folder, filename);
2863 msi_free(target_folder);
2864 msi_free(filename);
2866 buffer = MSI_RecordGetString(row,5);
2867 if (strchrW(buffer,'['))
2869 LPWSTR deformated;
2870 deformat_string(package,buffer,&deformated);
2871 IShellLinkW_SetPath(sl,deformated);
2872 msi_free(deformated);
2874 else
2876 FIXME("poorly handled shortcut format, advertised shortcut\n");
2877 IShellLinkW_SetPath(sl,comp->FullKeypath);
2880 if (!MSI_RecordIsNull(row,6))
2882 LPWSTR deformated;
2883 buffer = MSI_RecordGetString(row,6);
2884 deformat_string(package,buffer,&deformated);
2885 IShellLinkW_SetArguments(sl,deformated);
2886 msi_free(deformated);
2889 if (!MSI_RecordIsNull(row,7))
2891 buffer = MSI_RecordGetString(row,7);
2892 IShellLinkW_SetDescription(sl,buffer);
2895 if (!MSI_RecordIsNull(row,8))
2896 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2898 if (!MSI_RecordIsNull(row,9))
2900 LPWSTR Path;
2901 INT index;
2903 buffer = MSI_RecordGetString(row,9);
2905 Path = build_icon_path(package,buffer);
2906 index = MSI_RecordGetInteger(row,10);
2908 IShellLinkW_SetIconLocation(sl,Path,index);
2909 msi_free(Path);
2912 if (!MSI_RecordIsNull(row,11))
2913 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2915 if (!MSI_RecordIsNull(row,12))
2917 LPWSTR Path;
2918 buffer = MSI_RecordGetString(row,12);
2919 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2920 IShellLinkW_SetWorkingDirectory(sl,Path);
2921 msi_free(Path);
2924 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2925 IPersistFile_Save(pf,target_file,FALSE);
2927 msi_free(target_file);
2929 err:
2930 if (pf)
2931 IPersistFile_Release( pf );
2932 if (sl)
2933 IShellLinkW_Release( sl );
2935 return ERROR_SUCCESS;
2938 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2940 UINT rc;
2941 HRESULT res;
2942 MSIQUERY * view;
2943 static const WCHAR Query[] =
2944 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2945 '`','S','h','o','r','t','c','u','t','`',0};
2947 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2948 if (rc != ERROR_SUCCESS)
2949 return ERROR_SUCCESS;
2951 res = CoInitialize( NULL );
2952 if (FAILED (res))
2954 ERR("CoInitialize failed\n");
2955 return ERROR_FUNCTION_FAILED;
2958 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2959 msiobj_release(&view->hdr);
2961 CoUninitialize();
2963 return rc;
2966 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2968 MSIPACKAGE* package = (MSIPACKAGE*)param;
2969 HANDLE the_file;
2970 LPWSTR FilePath;
2971 LPCWSTR FileName;
2972 CHAR buffer[1024];
2973 DWORD sz;
2974 UINT rc;
2975 MSIRECORD *uirow;
2977 FileName = MSI_RecordGetString(row,1);
2978 if (!FileName)
2980 ERR("Unable to get FileName\n");
2981 return ERROR_SUCCESS;
2984 FilePath = build_icon_path(package,FileName);
2986 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2988 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2989 FILE_ATTRIBUTE_NORMAL, NULL);
2991 if (the_file == INVALID_HANDLE_VALUE)
2993 ERR("Unable to create file %s\n",debugstr_w(FilePath));
2994 msi_free(FilePath);
2995 return ERROR_SUCCESS;
3000 DWORD write;
3001 sz = 1024;
3002 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3003 if (rc != ERROR_SUCCESS)
3005 ERR("Failed to get stream\n");
3006 CloseHandle(the_file);
3007 DeleteFileW(FilePath);
3008 break;
3010 WriteFile(the_file,buffer,sz,&write,NULL);
3011 } while (sz == 1024);
3013 msi_free(FilePath);
3015 CloseHandle(the_file);
3017 uirow = MSI_CreateRecord(1);
3018 MSI_RecordSetStringW(uirow,1,FileName);
3019 ui_actiondata(package,szPublishProduct,uirow);
3020 msiobj_release( &uirow->hdr );
3022 return ERROR_SUCCESS;
3026 * 99% of the work done here is only done for
3027 * advertised installs. However this is where the
3028 * Icon table is processed and written out
3029 * so that is what I am going to do here.
3031 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3033 UINT rc;
3034 MSIQUERY * view;
3035 static const WCHAR Query[]=
3036 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3037 '`','I','c','o','n','`',0};
3038 /* for registry stuff */
3039 HKEY hkey=0;
3040 HKEY hukey=0;
3041 static const WCHAR szProductLanguage[] =
3042 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3043 static const WCHAR szARPProductIcon[] =
3044 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3045 static const WCHAR szProductVersion[] =
3046 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3047 DWORD langid;
3048 LPWSTR buffer;
3049 DWORD size;
3050 MSIHANDLE hDb, hSumInfo;
3052 /* write out icon files */
3054 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3055 if (rc == ERROR_SUCCESS)
3057 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3058 msiobj_release(&view->hdr);
3061 /* ok there is a lot more done here but i need to figure out what */
3063 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3064 if (rc != ERROR_SUCCESS)
3065 goto end;
3067 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3068 if (rc != ERROR_SUCCESS)
3069 goto end;
3072 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3073 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3074 msi_free(buffer);
3076 langid = msi_get_property_int( package, szProductLanguage, 0 );
3077 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3079 buffer = msi_dup_property( package, szARPProductIcon );
3080 if (buffer)
3082 LPWSTR path = build_icon_path(package,buffer);
3083 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3084 msi_free( path );
3086 msi_free(buffer);
3088 buffer = msi_dup_property( package, szProductVersion );
3089 if (buffer)
3091 DWORD verdword = build_version_dword(buffer);
3092 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3094 msi_free(buffer);
3096 /* FIXME: Need to write more keys to the user registry */
3098 hDb= alloc_msihandle( &package->db->hdr );
3099 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3100 MsiCloseHandle(hDb);
3101 if (rc == ERROR_SUCCESS)
3103 WCHAR guidbuffer[0x200];
3104 size = 0x200;
3105 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3106 guidbuffer, &size);
3107 if (rc == ERROR_SUCCESS)
3109 WCHAR squashed[GUID_SIZE];
3110 /* for now we only care about the first guid */
3111 LPWSTR ptr = strchrW(guidbuffer,';');
3112 if (ptr) *ptr = 0;
3113 squash_guid(guidbuffer,squashed);
3114 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3116 else
3118 ERR("Unable to query Revision_Number...\n");
3119 rc = ERROR_SUCCESS;
3121 MsiCloseHandle(hSumInfo);
3123 else
3125 ERR("Unable to open Summary Information\n");
3126 rc = ERROR_SUCCESS;
3129 end:
3131 RegCloseKey(hkey);
3132 RegCloseKey(hukey);
3134 return rc;
3137 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3139 MSIPACKAGE *package = (MSIPACKAGE*)param;
3140 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3141 LPWSTR deformated_section, deformated_key, deformated_value;
3142 LPWSTR folder, fullname = NULL;
3143 MSIRECORD * uirow;
3144 INT action;
3145 MSICOMPONENT *comp;
3146 static const WCHAR szWindowsFolder[] =
3147 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3149 component = MSI_RecordGetString(row, 8);
3150 comp = get_loaded_component(package,component);
3152 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3154 TRACE("Skipping ini file due to disabled component %s\n",
3155 debugstr_w(component));
3157 comp->Action = comp->Installed;
3159 return ERROR_SUCCESS;
3162 comp->Action = INSTALLSTATE_LOCAL;
3164 identifier = MSI_RecordGetString(row,1);
3165 filename = MSI_RecordGetString(row,2);
3166 dirproperty = MSI_RecordGetString(row,3);
3167 section = MSI_RecordGetString(row,4);
3168 key = MSI_RecordGetString(row,5);
3169 value = MSI_RecordGetString(row,6);
3170 action = MSI_RecordGetInteger(row,7);
3172 deformat_string(package,section,&deformated_section);
3173 deformat_string(package,key,&deformated_key);
3174 deformat_string(package,value,&deformated_value);
3176 if (dirproperty)
3178 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3179 if (!folder)
3180 folder = msi_dup_property( package, dirproperty );
3182 else
3183 folder = msi_dup_property( package, szWindowsFolder );
3185 if (!folder)
3187 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3188 goto cleanup;
3191 fullname = build_directory_name(2, folder, filename);
3193 if (action == 0)
3195 TRACE("Adding value %s to section %s in %s\n",
3196 debugstr_w(deformated_key), debugstr_w(deformated_section),
3197 debugstr_w(fullname));
3198 WritePrivateProfileStringW(deformated_section, deformated_key,
3199 deformated_value, fullname);
3201 else if (action == 1)
3203 WCHAR returned[10];
3204 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3205 returned, 10, fullname);
3206 if (returned[0] == 0)
3208 TRACE("Adding value %s to section %s in %s\n",
3209 debugstr_w(deformated_key), debugstr_w(deformated_section),
3210 debugstr_w(fullname));
3212 WritePrivateProfileStringW(deformated_section, deformated_key,
3213 deformated_value, fullname);
3216 else if (action == 3)
3217 FIXME("Append to existing section not yet implemented\n");
3219 uirow = MSI_CreateRecord(4);
3220 MSI_RecordSetStringW(uirow,1,identifier);
3221 MSI_RecordSetStringW(uirow,2,deformated_section);
3222 MSI_RecordSetStringW(uirow,3,deformated_key);
3223 MSI_RecordSetStringW(uirow,4,deformated_value);
3224 ui_actiondata(package,szWriteIniValues,uirow);
3225 msiobj_release( &uirow->hdr );
3226 cleanup:
3227 msi_free(fullname);
3228 msi_free(folder);
3229 msi_free(deformated_key);
3230 msi_free(deformated_value);
3231 msi_free(deformated_section);
3232 return ERROR_SUCCESS;
3235 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3237 UINT rc;
3238 MSIQUERY * view;
3239 static const WCHAR ExecSeqQuery[] =
3240 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3241 '`','I','n','i','F','i','l','e','`',0};
3243 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3244 if (rc != ERROR_SUCCESS)
3246 TRACE("no IniFile table\n");
3247 return ERROR_SUCCESS;
3250 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3251 msiobj_release(&view->hdr);
3252 return rc;
3255 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3257 MSIPACKAGE *package = (MSIPACKAGE*)param;
3258 LPCWSTR filename;
3259 LPWSTR FullName;
3260 MSIFILE *file;
3261 DWORD len;
3262 static const WCHAR ExeStr[] =
3263 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3264 static const WCHAR close[] = {'\"',0};
3265 STARTUPINFOW si;
3266 PROCESS_INFORMATION info;
3267 BOOL brc;
3268 MSIRECORD *uirow;
3269 LPWSTR uipath, p;
3271 memset(&si,0,sizeof(STARTUPINFOW));
3273 filename = MSI_RecordGetString(row,1);
3274 file = get_loaded_file( package, filename );
3276 if (!file)
3278 ERR("Unable to find file id %s\n",debugstr_w(filename));
3279 return ERROR_SUCCESS;
3282 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3284 FullName = msi_alloc(len*sizeof(WCHAR));
3285 strcpyW(FullName,ExeStr);
3286 strcatW( FullName, file->TargetPath );
3287 strcatW(FullName,close);
3289 TRACE("Registering %s\n",debugstr_w(FullName));
3290 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3291 &si, &info);
3293 if (brc)
3294 msi_dialog_check_messages(info.hProcess);
3296 msi_free(FullName);
3298 /* the UI chunk */
3299 uirow = MSI_CreateRecord( 2 );
3300 uipath = strdupW( file->TargetPath );
3301 p = strrchrW(uipath,'\\');
3302 if (p)
3303 p[1]=0;
3304 MSI_RecordSetStringW( uirow, 1, &p[2] );
3305 MSI_RecordSetStringW( uirow, 2, uipath);
3306 ui_actiondata( package, szSelfRegModules, uirow);
3307 msiobj_release( &uirow->hdr );
3308 msi_free( uipath );
3309 /* FIXME: call ui_progress? */
3311 return ERROR_SUCCESS;
3314 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3316 UINT rc;
3317 MSIQUERY * view;
3318 static const WCHAR ExecSeqQuery[] =
3319 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3320 '`','S','e','l','f','R','e','g','`',0};
3322 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3323 if (rc != ERROR_SUCCESS)
3325 TRACE("no SelfReg table\n");
3326 return ERROR_SUCCESS;
3329 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3330 msiobj_release(&view->hdr);
3332 return ERROR_SUCCESS;
3335 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3337 MSIFEATURE *feature;
3338 UINT rc;
3339 HKEY hkey=0;
3340 HKEY hukey=0;
3342 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3343 if (rc != ERROR_SUCCESS)
3344 goto end;
3346 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3347 if (rc != ERROR_SUCCESS)
3348 goto end;
3350 /* here the guids are base 85 encoded */
3351 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3353 ComponentList *cl;
3354 LPWSTR data = NULL;
3355 GUID clsid;
3356 INT size;
3357 BOOL absent = FALSE;
3358 MSIRECORD *uirow;
3360 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3361 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3362 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3363 absent = TRUE;
3365 size = 1;
3366 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3368 size += 21;
3370 if (feature->Feature_Parent)
3371 size += strlenW( feature->Feature_Parent )+2;
3373 data = msi_alloc(size * sizeof(WCHAR));
3375 data[0] = 0;
3376 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3378 MSICOMPONENT* component = cl->component;
3379 WCHAR buf[21];
3381 buf[0] = 0;
3382 if (component->ComponentId)
3384 TRACE("From %s\n",debugstr_w(component->ComponentId));
3385 CLSIDFromString(component->ComponentId, &clsid);
3386 encode_base85_guid(&clsid,buf);
3387 TRACE("to %s\n",debugstr_w(buf));
3388 strcatW(data,buf);
3391 if (feature->Feature_Parent)
3393 static const WCHAR sep[] = {'\2',0};
3394 strcatW(data,sep);
3395 strcatW(data,feature->Feature_Parent);
3398 msi_reg_set_val_str( hkey, feature->Feature, data );
3399 msi_free(data);
3401 size = 0;
3402 if (feature->Feature_Parent)
3403 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3404 if (!absent)
3406 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3407 (LPBYTE)feature->Feature_Parent,size);
3409 else
3411 size += 2*sizeof(WCHAR);
3412 data = msi_alloc(size);
3413 data[0] = 0x6;
3414 data[1] = 0;
3415 if (feature->Feature_Parent)
3416 strcpyW( &data[1], feature->Feature_Parent );
3417 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3418 (LPBYTE)data,size);
3419 msi_free(data);
3422 /* the UI chunk */
3423 uirow = MSI_CreateRecord( 1 );
3424 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3425 ui_actiondata( package, szPublishFeatures, uirow);
3426 msiobj_release( &uirow->hdr );
3427 /* FIXME: call ui_progress? */
3430 end:
3431 RegCloseKey(hkey);
3432 RegCloseKey(hukey);
3433 return rc;
3436 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3438 static const WCHAR installerPathFmt[] = {
3439 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3440 static const WCHAR fmt[] = {
3441 '%','s','\\',
3442 'I','n','s','t','a','l','l','e','r','\\',
3443 '%','x','.','m','s','i',0};
3444 static const WCHAR szOriginalDatabase[] =
3445 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3446 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3447 INT num, start;
3448 LPWSTR msiFilePath;
3449 BOOL r;
3451 /* copy the package locally */
3452 num = GetTickCount() & 0xffff;
3453 if (!num)
3454 num = 1;
3455 start = num;
3456 GetWindowsDirectoryW( windir, MAX_PATH );
3457 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3460 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3461 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3462 if (handle != INVALID_HANDLE_VALUE)
3464 CloseHandle(handle);
3465 break;
3467 if (GetLastError() != ERROR_FILE_EXISTS &&
3468 GetLastError() != ERROR_SHARING_VIOLATION)
3469 break;
3470 if (!(++num & 0xffff)) num = 1;
3471 sprintfW(packagefile,fmt,num);
3472 } while (num != start);
3474 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3475 create_full_pathW(path);
3477 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3479 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3480 r = CopyFileW( msiFilePath, packagefile, FALSE);
3481 msi_free( msiFilePath );
3483 if (!r)
3485 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3486 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3487 return ERROR_FUNCTION_FAILED;
3490 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3491 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3492 return ERROR_SUCCESS;
3495 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3497 LPWSTR prop, val, key;
3498 static const LPCSTR propval[] = {
3499 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3500 "ARPCONTACT", "Contact",
3501 "ARPCOMMENTS", "Comments",
3502 "ProductName", "DisplayName",
3503 "ProductVersion", "DisplayVersion",
3504 "ARPHELPLINK", "HelpLink",
3505 "ARPHELPTELEPHONE", "HelpTelephone",
3506 "ARPINSTALLLOCATION", "InstallLocation",
3507 "SourceDir", "InstallSource",
3508 "Manufacturer", "Publisher",
3509 "ARPREADME", "Readme",
3510 "ARPSIZE", "Size",
3511 "ARPURLINFOABOUT", "URLInfoAbout",
3512 "ARPURLUPDATEINFO", "URLUpdateInfo",
3513 NULL,
3515 const LPCSTR *p = propval;
3517 while( *p )
3519 prop = strdupAtoW( *p++ );
3520 key = strdupAtoW( *p++ );
3521 val = msi_dup_property( package, prop );
3522 msi_reg_set_val_str( hkey, key, val );
3523 msi_free(val);
3524 msi_free(key);
3525 msi_free(prop);
3527 return ERROR_SUCCESS;
3530 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3532 HKEY hkey=0;
3533 LPWSTR buffer = NULL;
3534 UINT rc;
3535 DWORD size, langid;
3536 static const WCHAR szWindowsInstaller[] =
3537 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3538 static const WCHAR szUpgradeCode[] =
3539 {'U','p','g','r','a','d','e','C','o','d','e',0};
3540 static const WCHAR modpath_fmt[] =
3541 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3542 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3543 static const WCHAR szModifyPath[] =
3544 {'M','o','d','i','f','y','P','a','t','h',0};
3545 static const WCHAR szUninstallString[] =
3546 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3547 static const WCHAR szEstimatedSize[] =
3548 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3549 static const WCHAR szProductLanguage[] =
3550 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3551 static const WCHAR szProductVersion[] =
3552 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3554 SYSTEMTIME systime;
3555 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3556 LPWSTR upgrade_code;
3557 WCHAR szDate[9];
3559 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3560 if (rc != ERROR_SUCCESS)
3561 return rc;
3563 /* dump all the info i can grab */
3564 /* FIXME: Flesh out more information */
3566 msi_write_uninstall_property_vals( package, hkey );
3568 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3570 msi_make_package_local( package, hkey );
3572 /* do ModifyPath and UninstallString */
3573 size = deformat_string(package,modpath_fmt,&buffer);
3574 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3575 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3576 msi_free(buffer);
3578 /* FIXME: Write real Estimated Size when we have it */
3579 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3581 GetLocalTime(&systime);
3582 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3583 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3585 langid = msi_get_property_int( package, szProductLanguage, 0 );
3586 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3588 buffer = msi_dup_property( package, szProductVersion );
3589 if (buffer)
3591 DWORD verdword = build_version_dword(buffer);
3593 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3594 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3595 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3597 msi_free(buffer);
3599 /* Handle Upgrade Codes */
3600 upgrade_code = msi_dup_property( package, szUpgradeCode );
3601 if (upgrade_code)
3603 HKEY hkey2;
3604 WCHAR squashed[33];
3605 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3606 squash_guid(package->ProductCode,squashed);
3607 msi_reg_set_val_str( hkey2, squashed, NULL );
3608 RegCloseKey(hkey2);
3609 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3610 squash_guid(package->ProductCode,squashed);
3611 msi_reg_set_val_str( hkey2, squashed, NULL );
3612 RegCloseKey(hkey2);
3614 msi_free(upgrade_code);
3617 RegCloseKey(hkey);
3619 /* FIXME: call ui_actiondata */
3621 return ERROR_SUCCESS;
3624 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3626 return execute_script(package,INSTALL_SCRIPT);
3629 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3631 UINT rc;
3633 /* turn off scheduleing */
3634 package->script->CurrentlyScripting= FALSE;
3636 /* first do the same as an InstallExecute */
3637 rc = ACTION_InstallExecute(package);
3638 if (rc != ERROR_SUCCESS)
3639 return rc;
3641 /* then handle Commit Actions */
3642 rc = execute_script(package,COMMIT_SCRIPT);
3644 return rc;
3647 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3649 static const WCHAR RunOnce[] = {
3650 'S','o','f','t','w','a','r','e','\\',
3651 'M','i','c','r','o','s','o','f','t','\\',
3652 'W','i','n','d','o','w','s','\\',
3653 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3654 'R','u','n','O','n','c','e',0};
3655 static const WCHAR InstallRunOnce[] = {
3656 'S','o','f','t','w','a','r','e','\\',
3657 'M','i','c','r','o','s','o','f','t','\\',
3658 'W','i','n','d','o','w','s','\\',
3659 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3660 'I','n','s','t','a','l','l','e','r','\\',
3661 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3663 static const WCHAR msiexec_fmt[] = {
3664 '%','s',
3665 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3666 '\"','%','s','\"',0};
3667 static const WCHAR install_fmt[] = {
3668 '/','I',' ','\"','%','s','\"',' ',
3669 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3670 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3671 WCHAR buffer[256], sysdir[MAX_PATH];
3672 HKEY hkey;
3673 WCHAR squished_pc[100];
3675 squash_guid(package->ProductCode,squished_pc);
3677 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3678 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3679 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3680 squished_pc);
3682 msi_reg_set_val_str( hkey, squished_pc, buffer );
3683 RegCloseKey(hkey);
3685 TRACE("Reboot command %s\n",debugstr_w(buffer));
3687 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3688 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3690 msi_reg_set_val_str( hkey, squished_pc, buffer );
3691 RegCloseKey(hkey);
3693 return ERROR_INSTALL_SUSPEND;
3696 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3698 DWORD attrib;
3699 UINT rc;
3701 * we are currently doing what should be done here in the top level Install
3702 * however for Adminastrative and uninstalls this step will be needed
3704 if (!package->PackagePath)
3705 return ERROR_SUCCESS;
3707 attrib = GetFileAttributesW(package->PackagePath);
3708 if (attrib == INVALID_FILE_ATTRIBUTES)
3710 LPWSTR prompt;
3711 LPWSTR msg;
3712 DWORD size = 0;
3714 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3715 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3716 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3717 if (rc == ERROR_MORE_DATA)
3719 prompt = msi_alloc(size * sizeof(WCHAR));
3720 MsiSourceListGetInfoW(package->ProductCode, NULL,
3721 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3722 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3724 else
3725 prompt = strdupW(package->PackagePath);
3727 msg = generate_error_string(package,1302,1,prompt);
3728 while(attrib == INVALID_FILE_ATTRIBUTES)
3730 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3731 if (rc == IDCANCEL)
3733 rc = ERROR_INSTALL_USEREXIT;
3734 break;
3736 attrib = GetFileAttributesW(package->PackagePath);
3738 msi_free(prompt);
3739 rc = ERROR_SUCCESS;
3741 else
3742 return ERROR_SUCCESS;
3744 return rc;
3747 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3749 HKEY hkey=0;
3750 LPWSTR buffer;
3751 LPWSTR productid;
3752 UINT rc,i;
3754 static const WCHAR szPropKeys[][80] =
3756 {'P','r','o','d','u','c','t','I','D',0},
3757 {'U','S','E','R','N','A','M','E',0},
3758 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3759 {0},
3762 static const WCHAR szRegKeys[][80] =
3764 {'P','r','o','d','u','c','t','I','D',0},
3765 {'R','e','g','O','w','n','e','r',0},
3766 {'R','e','g','C','o','m','p','a','n','y',0},
3767 {0},
3770 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3771 if (!productid)
3772 return ERROR_SUCCESS;
3774 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3775 if (rc != ERROR_SUCCESS)
3776 goto end;
3778 for( i = 0; szPropKeys[i][0]; i++ )
3780 buffer = msi_dup_property( package, szPropKeys[i] );
3781 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3782 msi_free( buffer );
3785 end:
3786 msi_free(productid);
3787 RegCloseKey(hkey);
3789 /* FIXME: call ui_actiondata */
3791 return ERROR_SUCCESS;
3795 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3797 UINT rc;
3799 package->script->InWhatSequence |= SEQUENCE_EXEC;
3800 rc = ACTION_ProcessExecSequence(package,FALSE);
3801 return rc;
3806 * Code based off of code located here
3807 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3809 * Using string index 4 (full font name) instead of 1 (family name)
3811 static LPWSTR load_ttfname_from(LPCWSTR filename)
3813 HANDLE handle;
3814 LPWSTR ret = NULL;
3815 int i;
3817 typedef struct _tagTT_OFFSET_TABLE{
3818 USHORT uMajorVersion;
3819 USHORT uMinorVersion;
3820 USHORT uNumOfTables;
3821 USHORT uSearchRange;
3822 USHORT uEntrySelector;
3823 USHORT uRangeShift;
3824 }TT_OFFSET_TABLE;
3826 typedef struct _tagTT_TABLE_DIRECTORY{
3827 char szTag[4]; /* table name */
3828 ULONG uCheckSum; /* Check sum */
3829 ULONG uOffset; /* Offset from beginning of file */
3830 ULONG uLength; /* length of the table in bytes */
3831 }TT_TABLE_DIRECTORY;
3833 typedef struct _tagTT_NAME_TABLE_HEADER{
3834 USHORT uFSelector; /* format selector. Always 0 */
3835 USHORT uNRCount; /* Name Records count */
3836 USHORT uStorageOffset; /* Offset for strings storage,
3837 * from start of the table */
3838 }TT_NAME_TABLE_HEADER;
3840 typedef struct _tagTT_NAME_RECORD{
3841 USHORT uPlatformID;
3842 USHORT uEncodingID;
3843 USHORT uLanguageID;
3844 USHORT uNameID;
3845 USHORT uStringLength;
3846 USHORT uStringOffset; /* from start of storage area */
3847 }TT_NAME_RECORD;
3849 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3850 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3852 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3853 FILE_ATTRIBUTE_NORMAL, 0 );
3854 if (handle != INVALID_HANDLE_VALUE)
3856 TT_TABLE_DIRECTORY tblDir;
3857 BOOL bFound = FALSE;
3858 TT_OFFSET_TABLE ttOffsetTable;
3859 DWORD dwRead;
3861 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3862 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3863 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3864 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3866 if (ttOffsetTable.uMajorVersion != 1 ||
3867 ttOffsetTable.uMinorVersion != 0)
3868 return NULL;
3870 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3872 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3873 if (strncmp(tblDir.szTag,"name",4)==0)
3875 bFound = TRUE;
3876 tblDir.uLength = SWAPLONG(tblDir.uLength);
3877 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3878 break;
3882 if (bFound)
3884 TT_NAME_TABLE_HEADER ttNTHeader;
3885 TT_NAME_RECORD ttRecord;
3887 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3888 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3889 &dwRead,NULL);
3891 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3892 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3893 bFound = FALSE;
3894 for(i=0; i<ttNTHeader.uNRCount; i++)
3896 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3897 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3898 /* 4 is the Full Font Name */
3899 if(ttRecord.uNameID == 4)
3901 int nPos;
3902 LPSTR buf;
3903 static LPCSTR tt = " (TrueType)";
3905 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3906 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3907 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3908 SetFilePointer(handle, tblDir.uOffset +
3909 ttRecord.uStringOffset +
3910 ttNTHeader.uStorageOffset,
3911 NULL, FILE_BEGIN);
3912 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3913 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3914 if (strlen(buf) > 0)
3916 strcat(buf,tt);
3917 ret = strdupAtoW(buf);
3918 msi_free(buf);
3919 break;
3922 msi_free(buf);
3923 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3927 CloseHandle(handle);
3929 else
3930 ERR("Unable to open font file %s\n", debugstr_w(filename));
3932 TRACE("Returning fontname %s\n",debugstr_w(ret));
3933 return ret;
3936 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3938 MSIPACKAGE *package = (MSIPACKAGE*)param;
3939 LPWSTR name;
3940 LPCWSTR filename;
3941 MSIFILE *file;
3942 static const WCHAR regfont1[] =
3943 {'S','o','f','t','w','a','r','e','\\',
3944 'M','i','c','r','o','s','o','f','t','\\',
3945 'W','i','n','d','o','w','s',' ','N','T','\\',
3946 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3947 'F','o','n','t','s',0};
3948 static const WCHAR regfont2[] =
3949 {'S','o','f','t','w','a','r','e','\\',
3950 'M','i','c','r','o','s','o','f','t','\\',
3951 'W','i','n','d','o','w','s','\\',
3952 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3953 'F','o','n','t','s',0};
3954 HKEY hkey1;
3955 HKEY hkey2;
3956 MSIRECORD *uirow;
3957 LPWSTR uipath, p;
3959 filename = MSI_RecordGetString( row, 1 );
3960 file = get_loaded_file( package, filename );
3961 if (!file)
3963 ERR("Unable to load file\n");
3964 return ERROR_SUCCESS;
3967 /* check to make sure that component is installed */
3968 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3970 TRACE("Skipping: Component not scheduled for install\n");
3971 return ERROR_SUCCESS;
3974 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3975 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3977 if (MSI_RecordIsNull(row,2))
3978 name = load_ttfname_from( file->TargetPath );
3979 else
3980 name = msi_dup_record_field(row,2);
3982 if (name)
3984 msi_reg_set_val_str( hkey1, name, file->FileName );
3985 msi_reg_set_val_str( hkey2, name, file->FileName );
3988 msi_free(name);
3989 RegCloseKey(hkey1);
3990 RegCloseKey(hkey2);
3992 /* the UI chunk */
3993 uirow = MSI_CreateRecord( 1 );
3994 uipath = strdupW( file->TargetPath );
3995 p = strrchrW(uipath,'\\');
3996 if (p) p++;
3997 else p = uipath;
3998 MSI_RecordSetStringW( uirow, 1, p );
3999 ui_actiondata( package, szRegisterFonts, uirow);
4000 msiobj_release( &uirow->hdr );
4001 msi_free( uipath );
4002 /* FIXME: call ui_progress? */
4004 return ERROR_SUCCESS;
4007 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4009 UINT rc;
4010 MSIQUERY * view;
4011 static const WCHAR ExecSeqQuery[] =
4012 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4013 '`','F','o','n','t','`',0};
4015 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4016 if (rc != ERROR_SUCCESS)
4018 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4019 return ERROR_SUCCESS;
4022 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4023 msiobj_release(&view->hdr);
4025 return ERROR_SUCCESS;
4028 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4030 MSIPACKAGE *package = (MSIPACKAGE*)param;
4031 LPCWSTR compgroupid=NULL;
4032 LPCWSTR feature=NULL;
4033 LPCWSTR text = NULL;
4034 LPCWSTR qualifier = NULL;
4035 LPCWSTR component = NULL;
4036 LPWSTR advertise = NULL;
4037 LPWSTR output = NULL;
4038 HKEY hkey;
4039 UINT rc = ERROR_SUCCESS;
4040 MSICOMPONENT *comp;
4041 DWORD sz = 0;
4042 MSIRECORD *uirow;
4044 component = MSI_RecordGetString(rec,3);
4045 comp = get_loaded_component(package,component);
4047 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4048 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4049 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4051 TRACE("Skipping: Component %s not scheduled for install\n",
4052 debugstr_w(component));
4054 return ERROR_SUCCESS;
4057 compgroupid = MSI_RecordGetString(rec,1);
4058 qualifier = MSI_RecordGetString(rec,2);
4060 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4061 if (rc != ERROR_SUCCESS)
4062 goto end;
4064 text = MSI_RecordGetString(rec,4);
4065 feature = MSI_RecordGetString(rec,5);
4067 advertise = create_component_advertise_string(package, comp, feature);
4069 sz = strlenW(advertise);
4071 if (text)
4072 sz += lstrlenW(text);
4074 sz+=3;
4075 sz *= sizeof(WCHAR);
4077 output = msi_alloc_zero(sz);
4078 strcpyW(output,advertise);
4079 msi_free(advertise);
4081 if (text)
4082 strcatW(output,text);
4084 msi_reg_set_val_multi_str( hkey, qualifier, output );
4086 end:
4087 RegCloseKey(hkey);
4088 msi_free(output);
4090 /* the UI chunk */
4091 uirow = MSI_CreateRecord( 2 );
4092 MSI_RecordSetStringW( uirow, 1, compgroupid );
4093 MSI_RecordSetStringW( uirow, 2, qualifier);
4094 ui_actiondata( package, szPublishComponents, uirow);
4095 msiobj_release( &uirow->hdr );
4096 /* FIXME: call ui_progress? */
4098 return rc;
4102 * At present I am ignorning the advertised components part of this and only
4103 * focusing on the qualified component sets
4105 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4107 UINT rc;
4108 MSIQUERY * view;
4109 static const WCHAR ExecSeqQuery[] =
4110 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4111 '`','P','u','b','l','i','s','h',
4112 'C','o','m','p','o','n','e','n','t','`',0};
4114 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4115 if (rc != ERROR_SUCCESS)
4116 return ERROR_SUCCESS;
4118 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4119 msiobj_release(&view->hdr);
4121 return rc;
4124 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4125 LPCSTR action, LPCWSTR table )
4127 static const WCHAR query[] = {
4128 'S','E','L','E','C','T',' ','*',' ',
4129 'F','R','O','M',' ','`','%','s','`',0 };
4130 MSIQUERY *view = NULL;
4131 DWORD count = 0;
4132 UINT r;
4134 r = MSI_OpenQuery( package->db, &view, query, table );
4135 if (r == ERROR_SUCCESS)
4137 r = MSI_IterateRecords(view, &count, NULL, package);
4138 msiobj_release(&view->hdr);
4141 if (count)
4142 FIXME("%s -> %lu ignored %s table values\n",
4143 action, count, debugstr_w(table));
4145 return ERROR_SUCCESS;
4148 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4150 TRACE("%p\n", package);
4151 return ERROR_SUCCESS;
4154 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4156 static const WCHAR table[] =
4157 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4158 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4161 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4163 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4164 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4167 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4169 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4170 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4173 static UINT ACTION_BindImage( MSIPACKAGE *package )
4175 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4176 return msi_unimplemented_action_stub( package, "BindImage", table );
4179 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4181 static const WCHAR table[] = {
4182 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4183 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4186 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4188 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4189 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4192 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4194 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4195 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4198 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4200 static const WCHAR table[] = {
4201 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4202 return msi_unimplemented_action_stub( package, "InstallServices", table );
4205 static UINT ACTION_StartServices( MSIPACKAGE *package )
4207 static const WCHAR table[] = {
4208 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4209 return msi_unimplemented_action_stub( package, "StartServices", table );
4212 static UINT ACTION_StopServices( MSIPACKAGE *package )
4214 static const WCHAR table[] = {
4215 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4216 return msi_unimplemented_action_stub( package, "StopServices", table );
4219 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4221 static const WCHAR table[] = {
4222 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4223 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4226 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4228 static const WCHAR table[] = {
4229 'E','n','v','i','r','o','n','m','e','n','t',0 };
4230 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4233 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4235 static const WCHAR table[] = {
4236 'E','n','v','i','r','o','n','m','e','n','t',0 };
4237 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4240 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4242 static const WCHAR table[] = {
4243 'M','s','i','A','s','s','e','m','b','l','y',0 };
4244 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4247 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4249 static const WCHAR table[] = {
4250 'M','s','i','A','s','s','e','m','b','l','y',0 };
4251 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4254 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4256 static const WCHAR table[] = { 'F','o','n','t',0 };
4257 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4260 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4262 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4263 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4266 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4268 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4269 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4272 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4274 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4275 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4278 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4280 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4281 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4284 static struct _actions StandardActions[] = {
4285 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4286 { szAppSearch, ACTION_AppSearch },
4287 { szBindImage, ACTION_BindImage },
4288 { szCCPSearch, ACTION_CCPSearch},
4289 { szCostFinalize, ACTION_CostFinalize },
4290 { szCostInitialize, ACTION_CostInitialize },
4291 { szCreateFolders, ACTION_CreateFolders },
4292 { szCreateShortcuts, ACTION_CreateShortcuts },
4293 { szDeleteServices, ACTION_DeleteServices },
4294 { szDisableRollback, NULL},
4295 { szDuplicateFiles, ACTION_DuplicateFiles },
4296 { szExecuteAction, ACTION_ExecuteAction },
4297 { szFileCost, ACTION_FileCost },
4298 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4299 { szForceReboot, ACTION_ForceReboot },
4300 { szInstallAdminPackage, NULL},
4301 { szInstallExecute, ACTION_InstallExecute },
4302 { szInstallExecuteAgain, ACTION_InstallExecute },
4303 { szInstallFiles, ACTION_InstallFiles},
4304 { szInstallFinalize, ACTION_InstallFinalize },
4305 { szInstallInitialize, ACTION_InstallInitialize },
4306 { szInstallSFPCatalogFile, NULL},
4307 { szInstallValidate, ACTION_InstallValidate },
4308 { szIsolateComponents, ACTION_IsolateComponents },
4309 { szLaunchConditions, ACTION_LaunchConditions },
4310 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4311 { szMoveFiles, ACTION_MoveFiles },
4312 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4313 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4314 { szInstallODBC, NULL},
4315 { szInstallServices, ACTION_InstallServices },
4316 { szPatchFiles, ACTION_PatchFiles },
4317 { szProcessComponents, ACTION_ProcessComponents },
4318 { szPublishComponents, ACTION_PublishComponents },
4319 { szPublishFeatures, ACTION_PublishFeatures },
4320 { szPublishProduct, ACTION_PublishProduct },
4321 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4322 { szRegisterComPlus, ACTION_RegisterComPlus},
4323 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4324 { szRegisterFonts, ACTION_RegisterFonts },
4325 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4326 { szRegisterProduct, ACTION_RegisterProduct },
4327 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4328 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4329 { szRegisterUser, ACTION_RegisterUser},
4330 { szRemoveDuplicateFiles, NULL},
4331 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4332 { szRemoveExistingProducts, NULL},
4333 { szRemoveFiles, ACTION_RemoveFiles},
4334 { szRemoveFolders, NULL},
4335 { szRemoveIniValues, ACTION_RemoveIniValues },
4336 { szRemoveODBC, NULL},
4337 { szRemoveRegistryValues, NULL},
4338 { szRemoveShortcuts, NULL},
4339 { szResolveSource, ACTION_ResolveSource},
4340 { szRMCCPSearch, ACTION_RMCCPSearch},
4341 { szScheduleReboot, NULL},
4342 { szSelfRegModules, ACTION_SelfRegModules },
4343 { szSelfUnregModules, ACTION_SelfUnregModules },
4344 { szSetODBCFolders, NULL},
4345 { szStartServices, ACTION_StartServices },
4346 { szStopServices, ACTION_StopServices },
4347 { szUnpublishComponents, NULL},
4348 { szUnpublishFeatures, NULL},
4349 { szUnregisterClassInfo, NULL},
4350 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4351 { szUnregisterExtensionInfo, NULL},
4352 { szUnregisterFonts, ACTION_UnregisterFonts },
4353 { szUnregisterMIMEInfo, NULL},
4354 { szUnregisterProgIdInfo, NULL},
4355 { szUnregisterTypeLibraries, NULL},
4356 { szValidateProductID, NULL},
4357 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4358 { szWriteIniValues, ACTION_WriteIniValues },
4359 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4360 { NULL, NULL},