usp10: Update tests in test_ScriptItemIzeShapePlace to match Windows results.
[wine/multimedia.git] / dlls / msi / action.c
blobbf4e2b0804dde63e7cb5795ac39d2add67dd0d8f
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 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 (!package)
888 ERR("package was null!\n");
889 return FALSE;
892 if (!run && !package->script->CurrentlyScripting)
893 run = TRUE;
895 if (!run)
897 if (strcmpW(action,szInstallFinalize) == 0 ||
898 strcmpW(action,szInstallExecute) == 0 ||
899 strcmpW(action,szInstallExecuteAgain) == 0)
900 run = TRUE;
903 i = 0;
904 while (StandardActions[i].action != NULL)
906 if (strcmpW(StandardActions[i].action, action)==0)
908 if (!run)
910 ui_actioninfo(package, action, TRUE, 0);
911 *rc = schedule_action(package,INSTALL_SCRIPT,action);
912 ui_actioninfo(package, action, FALSE, *rc);
914 else
916 ui_actionstart(package, action);
917 if (StandardActions[i].handler)
919 *rc = StandardActions[i].handler(package);
921 else
923 FIXME("unhandled standard action %s\n",debugstr_w(action));
924 *rc = ERROR_SUCCESS;
927 ret = TRUE;
928 break;
930 i++;
932 return ret;
935 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
936 UINT* rc, BOOL force )
938 BOOL ret=FALSE;
939 UINT arc;
941 arc = ACTION_CustomAction(package,action, force);
943 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
945 *rc = arc;
946 ret = TRUE;
948 return ret;
952 * A lot of actions are really important even if they don't do anything
953 * explicit... Lots of properties are set at the beginning of the installation
954 * CostFinalize does a bunch of work to translate the directories and such
956 * But until I get write access to the database that is hard, so I am going to
957 * hack it to see if I can get something to run.
959 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
961 UINT rc = ERROR_SUCCESS;
962 BOOL handled;
964 TRACE("Performing action (%s)\n",debugstr_w(action));
966 handled = ACTION_HandleStandardAction(package, action, &rc, force);
968 if (!handled)
969 handled = ACTION_HandleCustomAction(package, action, &rc, force);
971 if (!handled)
973 FIXME("unhandled msi action %s\n",debugstr_w(action));
974 rc = ERROR_FUNCTION_NOT_CALLED;
977 return rc;
980 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
982 UINT rc = ERROR_SUCCESS;
983 BOOL handled = FALSE;
985 TRACE("Performing action (%s)\n",debugstr_w(action));
987 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
989 if (!handled)
990 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
992 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
993 handled = TRUE;
995 if (!handled)
997 FIXME("unhandled msi action %s\n",debugstr_w(action));
998 rc = ERROR_FUNCTION_NOT_CALLED;
1001 return rc;
1006 * Actual Action Handlers
1009 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1011 MSIPACKAGE *package = (MSIPACKAGE*)param;
1012 LPCWSTR dir;
1013 LPWSTR full_path;
1014 MSIRECORD *uirow;
1015 MSIFOLDER *folder;
1017 dir = MSI_RecordGetString(row,1);
1018 if (!dir)
1020 ERR("Unable to get folder id\n");
1021 return ERROR_SUCCESS;
1024 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1025 if (!full_path)
1027 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1028 return ERROR_SUCCESS;
1031 TRACE("Folder is %s\n",debugstr_w(full_path));
1033 /* UI stuff */
1034 uirow = MSI_CreateRecord(1);
1035 MSI_RecordSetStringW(uirow,1,full_path);
1036 ui_actiondata(package,szCreateFolders,uirow);
1037 msiobj_release( &uirow->hdr );
1039 if (folder->State == 0)
1040 create_full_pathW(full_path);
1042 folder->State = 3;
1044 msi_free(full_path);
1045 return ERROR_SUCCESS;
1048 /* FIXME: probably should merge this with the above function */
1049 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1051 UINT rc = ERROR_SUCCESS;
1052 MSIFOLDER *folder;
1053 LPWSTR install_path;
1055 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1056 if (!install_path)
1057 return ERROR_FUNCTION_FAILED;
1059 /* create the path */
1060 if (folder->State == 0)
1062 create_full_pathW(install_path);
1063 folder->State = 2;
1065 msi_free(install_path);
1067 return rc;
1070 UINT msi_create_component_directories( MSIPACKAGE *package )
1072 MSICOMPONENT *comp;
1074 /* create all the folders required by the components are going to install */
1075 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1077 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1078 continue;
1079 msi_create_directory( package, comp->Directory );
1082 return ERROR_SUCCESS;
1086 * Also we cannot enable/disable components either, so for now I am just going
1087 * to do all the directories for all the components.
1089 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1091 static const WCHAR ExecSeqQuery[] =
1092 {'S','E','L','E','C','T',' ',
1093 '`','D','i','r','e','c','t','o','r','y','_','`',
1094 ' ','F','R','O','M',' ',
1095 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1096 UINT rc;
1097 MSIQUERY *view;
1099 /* create all the empty folders specified in the CreateFolder table */
1100 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1101 if (rc != ERROR_SUCCESS)
1102 return ERROR_SUCCESS;
1104 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1105 msiobj_release(&view->hdr);
1107 msi_create_component_directories( package );
1109 return rc;
1112 static MSICOMPONENT* load_component( MSIRECORD * row )
1114 MSICOMPONENT *comp;
1116 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1117 if (!comp)
1118 return comp;
1120 /* fill in the data */
1121 comp->Component = msi_dup_record_field( row, 1 );
1123 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1125 comp->ComponentId = msi_dup_record_field( row, 2 );
1126 comp->Directory = msi_dup_record_field( row, 3 );
1127 comp->Attributes = MSI_RecordGetInteger(row,4);
1128 comp->Condition = msi_dup_record_field( row, 5 );
1129 comp->KeyPath = msi_dup_record_field( row, 6 );
1131 comp->Installed = INSTALLSTATE_ABSENT;
1132 comp->Action = INSTALLSTATE_UNKNOWN;
1133 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1135 comp->Enabled = TRUE;
1137 return comp;
1140 typedef struct {
1141 MSIPACKAGE *package;
1142 MSIFEATURE *feature;
1143 } _ilfs;
1145 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1147 ComponentList *cl;
1149 cl = msi_alloc( sizeof (*cl) );
1150 if ( !cl )
1151 return ERROR_NOT_ENOUGH_MEMORY;
1152 cl->component = comp;
1153 list_add_tail( &feature->Components, &cl->entry );
1155 return ERROR_SUCCESS;
1158 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1160 _ilfs* ilfs= (_ilfs*)param;
1161 MSIPACKAGE *package = ilfs->package;
1162 MSIFEATURE *feature = ilfs->feature;
1163 MSICOMPONENT *comp;
1165 comp = load_component( row );
1166 if (!comp)
1167 return ERROR_FUNCTION_FAILED;
1169 list_add_tail( &package->components, &comp->entry );
1170 add_feature_component( feature, comp );
1172 TRACE("Loaded new component %p\n", comp);
1174 return ERROR_SUCCESS;
1177 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1179 _ilfs* ilfs= (_ilfs*)param;
1180 LPCWSTR component;
1181 DWORD rc;
1182 MSICOMPONENT *comp;
1183 MSIQUERY * view;
1184 static const WCHAR Query[] =
1185 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1186 '`','C','o','m','p','o','n','e','n','t','`',' ',
1187 'W','H','E','R','E',' ',
1188 '`','C','o','m','p','o','n','e','n','t','`',' ',
1189 '=','\'','%','s','\'',0};
1191 component = MSI_RecordGetString(row,1);
1193 /* check to see if the component is already loaded */
1194 comp = get_loaded_component( ilfs->package, component );
1195 if (comp)
1197 TRACE("Component %s already loaded\n", debugstr_w(component) );
1198 add_feature_component( ilfs->feature, comp );
1199 return ERROR_SUCCESS;
1202 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1203 if (rc != ERROR_SUCCESS)
1204 return ERROR_SUCCESS;
1206 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1207 msiobj_release( &view->hdr );
1209 return ERROR_SUCCESS;
1212 static UINT load_feature(MSIRECORD * row, LPVOID param)
1214 MSIPACKAGE* package = (MSIPACKAGE*)param;
1215 MSIFEATURE* feature;
1216 static const WCHAR Query1[] =
1217 {'S','E','L','E','C','T',' ',
1218 '`','C','o','m','p','o','n','e','n','t','_','`',
1219 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1220 'C','o','m','p','o','n','e','n','t','s','`',' ',
1221 'W','H','E','R','E',' ',
1222 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1223 MSIQUERY * view;
1224 UINT rc;
1225 _ilfs ilfs;
1227 /* fill in the data */
1229 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1230 if (!feature)
1231 return ERROR_NOT_ENOUGH_MEMORY;
1233 list_init( &feature->Components );
1235 feature->Feature = msi_dup_record_field( row, 1 );
1237 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1239 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1240 feature->Title = msi_dup_record_field( row, 3 );
1241 feature->Description = msi_dup_record_field( row, 4 );
1243 if (!MSI_RecordIsNull(row,5))
1244 feature->Display = MSI_RecordGetInteger(row,5);
1246 feature->Level= MSI_RecordGetInteger(row,6);
1247 feature->Directory = msi_dup_record_field( row, 7 );
1248 feature->Attributes = MSI_RecordGetInteger(row,8);
1250 feature->Installed = INSTALLSTATE_ABSENT;
1251 feature->Action = INSTALLSTATE_UNKNOWN;
1252 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1254 list_add_tail( &package->features, &feature->entry );
1256 /* load feature components */
1258 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1259 if (rc != ERROR_SUCCESS)
1260 return ERROR_SUCCESS;
1262 ilfs.package = package;
1263 ilfs.feature = feature;
1265 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1266 msiobj_release(&view->hdr);
1268 return ERROR_SUCCESS;
1271 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1273 if (!p)
1274 return p;
1275 p = strchrW(p, ch);
1276 if (!p)
1277 return p;
1278 *p = 0;
1279 return p+1;
1282 static UINT load_file(MSIRECORD *row, LPVOID param)
1284 MSIPACKAGE* package = (MSIPACKAGE*)param;
1285 LPCWSTR component;
1286 MSIFILE *file;
1288 /* fill in the data */
1290 file = msi_alloc_zero( sizeof (MSIFILE) );
1291 if (!file)
1292 return ERROR_NOT_ENOUGH_MEMORY;
1294 file->File = msi_dup_record_field( row, 1 );
1296 component = MSI_RecordGetString( row, 2 );
1297 file->Component = get_loaded_component( package, component );
1299 if (!file->Component)
1300 ERR("Unfound Component %s\n",debugstr_w(component));
1302 file->FileName = msi_dup_record_field( row, 3 );
1303 reduce_to_longfilename( file->FileName );
1305 file->ShortName = msi_dup_record_field( row, 3 );
1306 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1308 file->FileSize = MSI_RecordGetInteger( row, 4 );
1309 file->Version = msi_dup_record_field( row, 5 );
1310 file->Language = msi_dup_record_field( row, 6 );
1311 file->Attributes = MSI_RecordGetInteger( row, 7 );
1312 file->Sequence = MSI_RecordGetInteger( row, 8 );
1314 file->state = msifs_invalid;
1316 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1318 list_add_tail( &package->files, &file->entry );
1320 return ERROR_SUCCESS;
1323 static UINT load_all_files(MSIPACKAGE *package)
1325 MSIQUERY * view;
1326 UINT rc;
1327 static const WCHAR Query[] =
1328 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1330 '`','S','e','q','u','e','n','c','e','`', 0};
1332 if (!package)
1333 return ERROR_INVALID_HANDLE;
1335 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1336 if (rc != ERROR_SUCCESS)
1337 return ERROR_SUCCESS;
1339 rc = MSI_IterateRecords(view, NULL, load_file, package);
1340 msiobj_release(&view->hdr);
1342 return ERROR_SUCCESS;
1347 * I am not doing any of the costing functionality yet.
1348 * Mostly looking at doing the Component and Feature loading
1350 * The native MSI does A LOT of modification to tables here. Mostly adding
1351 * a lot of temporary columns to the Feature and Component tables.
1353 * note: Native msi also tracks the short filename. But I am only going to
1354 * track the long ones. Also looking at this directory table
1355 * it appears that the directory table does not get the parents
1356 * resolved base on property only based on their entries in the
1357 * directory table.
1359 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1361 MSIQUERY * view;
1362 UINT rc;
1363 static const WCHAR Query_all[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','e','a','t','u','r','e','`',0};
1366 static const WCHAR szCosting[] =
1367 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1368 static const WCHAR szZero[] = { '0', 0 };
1370 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1371 return ERROR_SUCCESS;
1373 MSI_SetPropertyW(package, szCosting, szZero);
1374 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1376 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1377 if (rc != ERROR_SUCCESS)
1378 return rc;
1380 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1381 msiobj_release(&view->hdr);
1383 load_all_files(package);
1385 return ERROR_SUCCESS;
1388 static UINT execute_script(MSIPACKAGE *package, UINT script )
1390 int i;
1391 UINT rc = ERROR_SUCCESS;
1393 TRACE("Executing Script %i\n",script);
1395 if (!package->script)
1397 ERR("no script!\n");
1398 return ERROR_FUNCTION_FAILED;
1401 for (i = 0; i < package->script->ActionCount[script]; i++)
1403 LPWSTR action;
1404 action = package->script->Actions[script][i];
1405 ui_actionstart(package, action);
1406 TRACE("Executing Action (%s)\n",debugstr_w(action));
1407 rc = ACTION_PerformAction(package, action, TRUE);
1408 msi_free(package->script->Actions[script][i]);
1409 if (rc != ERROR_SUCCESS)
1410 break;
1412 msi_free(package->script->Actions[script]);
1414 package->script->ActionCount[script] = 0;
1415 package->script->Actions[script] = NULL;
1416 return rc;
1419 static UINT ACTION_FileCost(MSIPACKAGE *package)
1421 return ERROR_SUCCESS;
1424 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1426 static const WCHAR Query[] =
1427 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1428 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1429 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1430 ' ','=',' ','\'','%','s','\'',
1432 static const WCHAR szDot[] = { '.',0 };
1433 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1434 LPCWSTR parent;
1435 MSIRECORD *row;
1436 MSIFOLDER *folder;
1438 TRACE("Looking for dir %s\n",debugstr_w(dir));
1440 folder = get_loaded_folder( package, dir );
1441 if (folder)
1442 return folder;
1444 TRACE("Working to load %s\n",debugstr_w(dir));
1446 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1447 if (!folder)
1448 return NULL;
1450 folder->Directory = strdupW(dir);
1452 row = MSI_QueryGetRecord(package->db, Query, dir);
1453 if (!row)
1454 return NULL;
1456 p = msi_dup_record_field(row, 3);
1458 /* split src and target dir */
1459 tgt_short = p;
1460 src_short = folder_split_path( p, ':' );
1462 /* split the long and short paths */
1463 tgt_long = folder_split_path( tgt_short, '|' );
1464 src_long = folder_split_path( src_short, '|' );
1466 /* check for root dirs */
1467 if (!lstrcmpW(szDot, tgt_short))
1468 tgt_short = NULL;
1469 if (!lstrcmpW(szDot, tgt_long))
1470 tgt_long = NULL;
1472 if (!tgt_long)
1473 tgt_long = tgt_short;
1475 if (!src_short) {
1476 src_short = tgt_short;
1477 src_long = tgt_long;
1480 if (!src_long)
1481 src_long = src_short;
1483 /* FIXME: use the target short path too */
1484 folder->TargetDefault = strdupW(tgt_long);
1485 folder->SourceShortPath = strdupW(src_short);
1486 folder->SourceLongPath = strdupW(src_long);
1487 msi_free(p);
1489 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1490 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1491 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1493 parent = MSI_RecordGetString(row, 2);
1494 if (parent)
1496 folder->Parent = load_folder( package, parent );
1497 if ( folder->Parent )
1498 TRACE("loaded parent %p %s\n", folder->Parent,
1499 debugstr_w(folder->Parent->Directory));
1500 else
1501 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1504 folder->Property = msi_dup_property( package, dir );
1506 msiobj_release(&row->hdr);
1508 list_add_tail( &package->folders, &folder->entry );
1510 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1512 return folder;
1515 /* scan for and update current install states */
1516 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1518 MSICOMPONENT *comp;
1519 MSIFEATURE *feature;
1521 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1523 INSTALLSTATE res;
1524 res = MsiGetComponentPathW( package->ProductCode,
1525 comp->ComponentId, NULL, NULL);
1526 if (res < 0)
1527 res = INSTALLSTATE_ABSENT;
1528 comp->Installed = res;
1531 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1533 ComponentList *cl;
1534 INSTALLSTATE res = -10;
1536 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1538 comp= cl->component;
1540 if (res == -10)
1541 res = comp->Installed;
1542 else
1544 if (res == comp->Installed)
1545 continue;
1547 if (res != comp->Installed)
1548 res = INSTALLSTATE_INCOMPLETE;
1551 feature->Installed = res;
1555 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1556 INSTALLSTATE state)
1558 static const WCHAR all[]={'A','L','L',0};
1559 LPWSTR override;
1560 MSIFEATURE *feature;
1562 override = msi_dup_property( package, property );
1563 if (!override)
1564 return FALSE;
1566 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1568 if (strcmpiW(override,all)==0)
1570 feature->ActionRequest= state;
1571 feature->Action = state;
1573 else
1575 LPWSTR ptr = override;
1576 LPWSTR ptr2 = strchrW(override,',');
1578 while (ptr)
1580 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1581 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1583 feature->ActionRequest= state;
1584 feature->Action = state;
1585 break;
1587 if (ptr2)
1589 ptr=ptr2+1;
1590 ptr2 = strchrW(ptr,',');
1592 else
1593 break;
1597 msi_free(override);
1599 return TRUE;
1602 static UINT SetFeatureStates(MSIPACKAGE *package)
1604 int install_level;
1605 static const WCHAR szlevel[] =
1606 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1607 static const WCHAR szAddLocal[] =
1608 {'A','D','D','L','O','C','A','L',0};
1609 static const WCHAR szRemove[] =
1610 {'R','E','M','O','V','E',0};
1611 static const WCHAR szReinstall[] =
1612 {'R','E','I','N','S','T','A','L','L',0};
1613 BOOL override = FALSE;
1614 MSICOMPONENT* component;
1615 MSIFEATURE *feature;
1618 /* I do not know if this is where it should happen.. but */
1620 TRACE("Checking Install Level\n");
1622 install_level = msi_get_property_int( package, szlevel, 1 );
1624 /* ok hereis the _real_ rub
1625 * all these activation/deactivation things happen in order and things
1626 * later on the list override things earlier on the list.
1627 * 1) INSTALLLEVEL processing
1628 * 2) ADDLOCAL
1629 * 3) REMOVE
1630 * 4) ADDSOURCE
1631 * 5) ADDDEFAULT
1632 * 6) REINSTALL
1633 * 7) COMPADDLOCAL
1634 * 8) COMPADDSOURCE
1635 * 9) FILEADDLOCAL
1636 * 10) FILEADDSOURCE
1637 * 11) FILEADDDEFAULT
1638 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1639 * ignored for all the features. seems strange, especially since it is not
1640 * documented anywhere, but it is how it works.
1642 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1643 * REMOVE are the big ones, since we don't handle administrative installs
1644 * yet anyway.
1646 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1647 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1648 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1650 if (!override)
1652 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1654 BOOL feature_state = ((feature->Level > 0) &&
1655 (feature->Level <= install_level));
1657 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1659 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1661 feature->ActionRequest = INSTALLSTATE_SOURCE;
1662 feature->Action = INSTALLSTATE_SOURCE;
1664 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1666 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1667 feature->Action = INSTALLSTATE_ADVERTISED;
1669 else
1671 feature->ActionRequest = INSTALLSTATE_LOCAL;
1672 feature->Action = INSTALLSTATE_LOCAL;
1677 else
1679 /* set the Preselected Property */
1680 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1681 static const WCHAR szOne[] = { '1', 0 };
1683 MSI_SetPropertyW(package,szPreselected,szOne);
1687 * now we want to enable or disable components base on feature
1690 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1692 ComponentList *cl;
1694 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1695 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1696 feature->ActionRequest);
1698 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1700 component = cl->component;
1702 if (!component->Enabled)
1704 component->Action = INSTALLSTATE_UNKNOWN;
1705 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1707 else
1709 if (feature->Action == INSTALLSTATE_LOCAL)
1711 component->Action = INSTALLSTATE_LOCAL;
1712 component->ActionRequest = INSTALLSTATE_LOCAL;
1714 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1716 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1717 (component->Action == INSTALLSTATE_ABSENT) ||
1718 (component->Action == INSTALLSTATE_ADVERTISED))
1721 component->Action = INSTALLSTATE_SOURCE;
1722 component->ActionRequest = INSTALLSTATE_SOURCE;
1725 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1727 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1728 (component->Action == INSTALLSTATE_ABSENT))
1731 component->Action = INSTALLSTATE_ADVERTISED;
1732 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1735 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1737 if (component->Action == INSTALLSTATE_UNKNOWN)
1739 component->Action = INSTALLSTATE_ABSENT;
1740 component->ActionRequest = INSTALLSTATE_ABSENT;
1747 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1749 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1750 debugstr_w(component->Component), component->Installed,
1751 component->Action, component->ActionRequest);
1755 return ERROR_SUCCESS;
1758 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1760 MSIPACKAGE *package = (MSIPACKAGE*)param;
1761 LPCWSTR name;
1762 LPWSTR path;
1764 name = MSI_RecordGetString(row,1);
1766 /* This helper function now does ALL the work */
1767 TRACE("Dir %s ...\n",debugstr_w(name));
1768 load_folder(package,name);
1769 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1770 TRACE("resolves to %s\n",debugstr_w(path));
1771 msi_free(path);
1773 return ERROR_SUCCESS;
1776 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1778 MSIPACKAGE *package = (MSIPACKAGE*)param;
1779 LPCWSTR name;
1780 MSIFEATURE *feature;
1782 name = MSI_RecordGetString( row, 1 );
1784 feature = get_loaded_feature( package, name );
1785 if (!feature)
1786 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1787 else
1789 LPCWSTR Condition;
1790 Condition = MSI_RecordGetString(row,3);
1792 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1794 int level = MSI_RecordGetInteger(row,2);
1795 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1796 feature->Level = level;
1799 return ERROR_SUCCESS;
1804 * A lot is done in this function aside from just the costing.
1805 * The costing needs to be implemented at some point but for now I am going
1806 * to focus on the directory building
1809 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1811 static const WCHAR ExecSeqQuery[] =
1812 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1813 '`','D','i','r','e','c','t','o','r','y','`',0};
1814 static const WCHAR ConditionQuery[] =
1815 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1816 '`','C','o','n','d','i','t','i','o','n','`',0};
1817 static const WCHAR szCosting[] =
1818 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1819 static const WCHAR szlevel[] =
1820 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1821 static const WCHAR szOne[] = { '1', 0 };
1822 MSICOMPONENT *comp;
1823 MSIFILE *file;
1824 UINT rc;
1825 MSIQUERY * view;
1826 LPWSTR level;
1828 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1829 return ERROR_SUCCESS;
1831 TRACE("Building Directory properties\n");
1833 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1834 if (rc == ERROR_SUCCESS)
1836 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1837 package);
1838 msiobj_release(&view->hdr);
1841 TRACE("File calculations\n");
1843 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1845 MSICOMPONENT* comp = file->Component;
1846 LPWSTR p;
1848 if (!comp)
1849 continue;
1851 /* calculate target */
1852 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1854 msi_free(file->TargetPath);
1856 TRACE("file %s is named %s\n",
1857 debugstr_w(file->File),debugstr_w(file->FileName));
1859 file->TargetPath = build_directory_name(2, p, file->FileName);
1861 msi_free(p);
1863 TRACE("file %s resolves to %s\n",
1864 debugstr_w(file->File),debugstr_w(file->TargetPath));
1866 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1868 file->state = msifs_missing;
1869 comp->Cost += file->FileSize;
1870 continue;
1873 if (file->Version)
1875 DWORD handle;
1876 DWORD versize;
1877 UINT sz;
1878 LPVOID version;
1879 static WCHAR name[] = {'\\',0};
1880 static const WCHAR name_fmt[] =
1881 {'%','u','.','%','u','.','%','u','.','%','u',0};
1882 WCHAR filever[0x100];
1883 VS_FIXEDFILEINFO *lpVer;
1885 TRACE("Version comparison..\n");
1886 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1887 version = msi_alloc(versize);
1888 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1890 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1892 sprintfW(filever,name_fmt,
1893 HIWORD(lpVer->dwFileVersionMS),
1894 LOWORD(lpVer->dwFileVersionMS),
1895 HIWORD(lpVer->dwFileVersionLS),
1896 LOWORD(lpVer->dwFileVersionLS));
1898 TRACE("new %s old %s\n", debugstr_w(file->Version),
1899 debugstr_w(filever));
1900 if (strcmpiW(filever,file->Version)<0)
1902 file->state = msifs_overwrite;
1903 /* FIXME: cost should be diff in size */
1904 comp->Cost += file->FileSize;
1906 else
1907 file->state = msifs_present;
1908 msi_free(version);
1910 else
1911 file->state = msifs_present;
1914 TRACE("Evaluating Condition Table\n");
1916 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1917 if (rc == ERROR_SUCCESS)
1919 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1920 package);
1921 msiobj_release(&view->hdr);
1924 TRACE("Enabling or Disabling Components\n");
1925 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1927 if (comp->Condition)
1929 if (MSI_EvaluateConditionW(package,
1930 comp->Condition) == MSICONDITION_FALSE)
1932 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1933 comp->Enabled = FALSE;
1938 MSI_SetPropertyW(package,szCosting,szOne);
1939 /* set default run level if not set */
1940 level = msi_dup_property( package, szlevel );
1941 if (!level)
1942 MSI_SetPropertyW(package,szlevel, szOne);
1943 msi_free(level);
1945 ACTION_UpdateInstallStates(package);
1947 return SetFeatureStates(package);
1950 /* OK this value is "interpreted" and then formatted based on the
1951 first few characters */
1952 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1953 DWORD *size)
1955 LPSTR data = NULL;
1956 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1958 if (value[1]=='x')
1960 LPWSTR ptr;
1961 CHAR byte[5];
1962 LPWSTR deformated = NULL;
1963 int count;
1965 deformat_string(package, &value[2], &deformated);
1967 /* binary value type */
1968 ptr = deformated;
1969 *type = REG_BINARY;
1970 if (strlenW(ptr)%2)
1971 *size = (strlenW(ptr)/2)+1;
1972 else
1973 *size = strlenW(ptr)/2;
1975 data = msi_alloc(*size);
1977 byte[0] = '0';
1978 byte[1] = 'x';
1979 byte[4] = 0;
1980 count = 0;
1981 /* if uneven pad with a zero in front */
1982 if (strlenW(ptr)%2)
1984 byte[2]= '0';
1985 byte[3]= *ptr;
1986 ptr++;
1987 data[count] = (BYTE)strtol(byte,NULL,0);
1988 count ++;
1989 TRACE("Uneven byte count\n");
1991 while (*ptr)
1993 byte[2]= *ptr;
1994 ptr++;
1995 byte[3]= *ptr;
1996 ptr++;
1997 data[count] = (BYTE)strtol(byte,NULL,0);
1998 count ++;
2000 msi_free(deformated);
2002 TRACE("Data %li bytes(%i)\n",*size,count);
2004 else
2006 LPWSTR deformated;
2007 LPWSTR p;
2008 DWORD d = 0;
2009 deformat_string(package, &value[1], &deformated);
2011 *type=REG_DWORD;
2012 *size = sizeof(DWORD);
2013 data = msi_alloc(*size);
2014 p = deformated;
2015 if (*p == '-')
2016 p++;
2017 while (*p)
2019 if ( (*p < '0') || (*p > '9') )
2020 break;
2021 d *= 10;
2022 d += (*p - '0');
2023 p++;
2025 if (deformated[0] == '-')
2026 d = -d;
2027 *(LPDWORD)data = d;
2028 TRACE("DWORD %li\n",*(LPDWORD)data);
2030 msi_free(deformated);
2033 else
2035 static const WCHAR szMulti[] = {'[','~',']',0};
2036 LPCWSTR ptr;
2037 *type=REG_SZ;
2039 if (value[0]=='#')
2041 if (value[1]=='%')
2043 ptr = &value[2];
2044 *type=REG_EXPAND_SZ;
2046 else
2047 ptr = &value[1];
2049 else
2050 ptr=value;
2052 if (strstrW(value,szMulti))
2053 *type = REG_MULTI_SZ;
2055 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2057 return data;
2060 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2062 MSIPACKAGE *package = (MSIPACKAGE*)param;
2063 static const WCHAR szHCR[] =
2064 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2065 'R','O','O','T','\\',0};
2066 static const WCHAR szHCU[] =
2067 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2068 'U','S','E','R','\\',0};
2069 static const WCHAR szHLM[] =
2070 {'H','K','E','Y','_','L','O','C','A','L','_',
2071 'M','A','C','H','I','N','E','\\',0};
2072 static const WCHAR szHU[] =
2073 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2075 LPSTR value_data = NULL;
2076 HKEY root_key, hkey;
2077 DWORD type,size;
2078 LPWSTR deformated;
2079 LPCWSTR szRoot, component, name, key, value;
2080 MSICOMPONENT *comp;
2081 MSIRECORD * uirow;
2082 LPWSTR uikey;
2083 INT root;
2084 BOOL check_first = FALSE;
2085 UINT rc;
2087 ui_progress(package,2,0,0,0);
2089 value = NULL;
2090 key = NULL;
2091 uikey = NULL;
2092 name = NULL;
2094 component = MSI_RecordGetString(row, 6);
2095 comp = get_loaded_component(package,component);
2096 if (!comp)
2097 return ERROR_SUCCESS;
2099 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2101 TRACE("Skipping write due to disabled component %s\n",
2102 debugstr_w(component));
2104 comp->Action = comp->Installed;
2106 return ERROR_SUCCESS;
2109 comp->Action = INSTALLSTATE_LOCAL;
2111 name = MSI_RecordGetString(row, 4);
2112 if( MSI_RecordIsNull(row,5) && name )
2114 /* null values can have special meanings */
2115 if (name[0]=='-' && name[1] == 0)
2116 return ERROR_SUCCESS;
2117 else if ((name[0]=='+' && name[1] == 0) ||
2118 (name[0] == '*' && name[1] == 0))
2119 name = NULL;
2120 check_first = TRUE;
2123 root = MSI_RecordGetInteger(row,2);
2124 key = MSI_RecordGetString(row, 3);
2126 /* get the root key */
2127 switch (root)
2129 case -1:
2131 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2132 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2133 if (all_users && all_users[0] == '1')
2135 root_key = HKEY_LOCAL_MACHINE;
2136 szRoot = szHLM;
2138 else
2140 root_key = HKEY_CURRENT_USER;
2141 szRoot = szHCU;
2143 msi_free(all_users);
2145 break;
2146 case 0: root_key = HKEY_CLASSES_ROOT;
2147 szRoot = szHCR;
2148 break;
2149 case 1: root_key = HKEY_CURRENT_USER;
2150 szRoot = szHCU;
2151 break;
2152 case 2: root_key = HKEY_LOCAL_MACHINE;
2153 szRoot = szHLM;
2154 break;
2155 case 3: root_key = HKEY_USERS;
2156 szRoot = szHU;
2157 break;
2158 default:
2159 ERR("Unknown root %i\n",root);
2160 root_key=NULL;
2161 szRoot = NULL;
2162 break;
2164 if (!root_key)
2165 return ERROR_SUCCESS;
2167 deformat_string(package, key , &deformated);
2168 size = strlenW(deformated) + strlenW(szRoot) + 1;
2169 uikey = msi_alloc(size*sizeof(WCHAR));
2170 strcpyW(uikey,szRoot);
2171 strcatW(uikey,deformated);
2173 if (RegCreateKeyW( root_key, deformated, &hkey))
2175 ERR("Could not create key %s\n",debugstr_w(deformated));
2176 msi_free(deformated);
2177 msi_free(uikey);
2178 return ERROR_SUCCESS;
2180 msi_free(deformated);
2182 value = MSI_RecordGetString(row,5);
2183 if (value)
2184 value_data = parse_value(package, value, &type, &size);
2185 else
2187 static const WCHAR szEmpty[] = {0};
2188 value_data = (LPSTR)strdupW(szEmpty);
2189 size = 0;
2190 type = REG_SZ;
2193 deformat_string(package, name, &deformated);
2195 /* get the double nulls to terminate SZ_MULTI */
2196 if (type == REG_MULTI_SZ)
2197 size +=sizeof(WCHAR);
2199 if (!check_first)
2201 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2202 debugstr_w(uikey));
2203 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2205 else
2207 DWORD sz = 0;
2208 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2209 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2211 TRACE("value %s of %s checked already exists\n",
2212 debugstr_w(deformated), debugstr_w(uikey));
2214 else
2216 TRACE("Checked and setting value %s of %s\n",
2217 debugstr_w(deformated), debugstr_w(uikey));
2218 if (deformated || size)
2219 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2222 RegCloseKey(hkey);
2224 uirow = MSI_CreateRecord(3);
2225 MSI_RecordSetStringW(uirow,2,deformated);
2226 MSI_RecordSetStringW(uirow,1,uikey);
2228 if (type == REG_SZ)
2229 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2230 else
2231 MSI_RecordSetStringW(uirow,3,value);
2233 ui_actiondata(package,szWriteRegistryValues,uirow);
2234 msiobj_release( &uirow->hdr );
2236 msi_free(value_data);
2237 msi_free(deformated);
2238 msi_free(uikey);
2240 return ERROR_SUCCESS;
2243 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2245 UINT rc;
2246 MSIQUERY * view;
2247 static const WCHAR ExecSeqQuery[] =
2248 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2249 '`','R','e','g','i','s','t','r','y','`',0 };
2251 if (!package)
2252 return ERROR_INVALID_HANDLE;
2254 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2255 if (rc != ERROR_SUCCESS)
2256 return ERROR_SUCCESS;
2258 /* increment progress bar each time action data is sent */
2259 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2261 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2263 msiobj_release(&view->hdr);
2264 return rc;
2267 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2269 package->script->CurrentlyScripting = TRUE;
2271 return ERROR_SUCCESS;
2275 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2277 MSICOMPONENT *comp;
2278 DWORD progress = 0;
2279 DWORD total = 0;
2280 static const WCHAR q1[]=
2281 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2282 '`','R','e','g','i','s','t','r','y','`',0};
2283 UINT rc;
2284 MSIQUERY * view;
2285 MSIFEATURE *feature;
2286 MSIFILE *file;
2288 TRACE("InstallValidate\n");
2290 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2291 if (rc == ERROR_SUCCESS)
2293 MSI_IterateRecords( view, &progress, NULL, package );
2294 msiobj_release( &view->hdr );
2295 total += progress * REG_PROGRESS_VALUE;
2298 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2299 total += COMPONENT_PROGRESS_VALUE;
2301 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2302 total += file->FileSize;
2304 ui_progress(package,0,total,0,0);
2306 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2308 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2309 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2310 feature->ActionRequest);
2313 return ERROR_SUCCESS;
2316 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2318 MSIPACKAGE* package = (MSIPACKAGE*)param;
2319 LPCWSTR cond = NULL;
2320 LPCWSTR message = NULL;
2321 static const WCHAR title[]=
2322 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2324 cond = MSI_RecordGetString(row,1);
2326 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2328 LPWSTR deformated;
2329 message = MSI_RecordGetString(row,2);
2330 deformat_string(package,message,&deformated);
2331 MessageBoxW(NULL,deformated,title,MB_OK);
2332 msi_free(deformated);
2333 return ERROR_FUNCTION_FAILED;
2336 return ERROR_SUCCESS;
2339 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2341 UINT rc;
2342 MSIQUERY * view = NULL;
2343 static const WCHAR ExecSeqQuery[] =
2344 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2345 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2347 TRACE("Checking launch conditions\n");
2349 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2350 if (rc != ERROR_SUCCESS)
2351 return ERROR_SUCCESS;
2353 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2354 msiobj_release(&view->hdr);
2356 return rc;
2359 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2362 if (!cmp->KeyPath)
2363 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2365 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2367 MSIRECORD * row = 0;
2368 UINT root,len;
2369 LPWSTR deformated,buffer,deformated_name;
2370 LPCWSTR key,name;
2371 static const WCHAR ExecSeqQuery[] =
2372 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2373 '`','R','e','g','i','s','t','r','y','`',' ',
2374 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2375 ' ','=',' ' ,'\'','%','s','\'',0 };
2376 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2377 static const WCHAR fmt2[]=
2378 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2380 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2381 if (!row)
2382 return NULL;
2384 root = MSI_RecordGetInteger(row,2);
2385 key = MSI_RecordGetString(row, 3);
2386 name = MSI_RecordGetString(row, 4);
2387 deformat_string(package, key , &deformated);
2388 deformat_string(package, name, &deformated_name);
2390 len = strlenW(deformated) + 6;
2391 if (deformated_name)
2392 len+=strlenW(deformated_name);
2394 buffer = msi_alloc( len *sizeof(WCHAR));
2396 if (deformated_name)
2397 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2398 else
2399 sprintfW(buffer,fmt,root,deformated);
2401 msi_free(deformated);
2402 msi_free(deformated_name);
2403 msiobj_release(&row->hdr);
2405 return buffer;
2407 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2409 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2410 return NULL;
2412 else
2414 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2416 if (file)
2417 return strdupW( file->TargetPath );
2419 return NULL;
2422 static HKEY openSharedDLLsKey(void)
2424 HKEY hkey=0;
2425 static const WCHAR path[] =
2426 {'S','o','f','t','w','a','r','e','\\',
2427 'M','i','c','r','o','s','o','f','t','\\',
2428 'W','i','n','d','o','w','s','\\',
2429 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2430 'S','h','a','r','e','d','D','L','L','s',0};
2432 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2433 return hkey;
2436 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2438 HKEY hkey;
2439 DWORD count=0;
2440 DWORD type;
2441 DWORD sz = sizeof(count);
2442 DWORD rc;
2444 hkey = openSharedDLLsKey();
2445 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2446 if (rc != ERROR_SUCCESS)
2447 count = 0;
2448 RegCloseKey(hkey);
2449 return count;
2452 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2454 HKEY hkey;
2456 hkey = openSharedDLLsKey();
2457 if (count > 0)
2458 msi_reg_set_val_dword( hkey, path, count );
2459 else
2460 RegDeleteValueW(hkey,path);
2461 RegCloseKey(hkey);
2462 return count;
2466 * Return TRUE if the count should be written out and FALSE if not
2468 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2470 MSIFEATURE *feature;
2471 INT count = 0;
2472 BOOL write = FALSE;
2474 /* only refcount DLLs */
2475 if (comp->KeyPath == NULL ||
2476 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2477 comp->Attributes & msidbComponentAttributesODBCDataSource)
2478 write = FALSE;
2479 else
2481 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2482 write = (count > 0);
2484 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2485 write = TRUE;
2488 /* increment counts */
2489 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2491 ComponentList *cl;
2493 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2494 continue;
2496 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2498 if ( cl->component == comp )
2499 count++;
2503 /* decrement counts */
2504 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2506 ComponentList *cl;
2508 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2509 continue;
2511 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2513 if ( cl->component == comp )
2514 count--;
2518 /* ref count all the files in the component */
2519 if (write)
2521 MSIFILE *file;
2523 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2525 if (file->Component == comp)
2526 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2530 /* add a count for permenent */
2531 if (comp->Attributes & msidbComponentAttributesPermanent)
2532 count ++;
2534 comp->RefCount = count;
2536 if (write)
2537 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2541 * Ok further analysis makes me think that this work is
2542 * actually done in the PublishComponents and PublishFeatures
2543 * step, and not here. It appears like the keypath and all that is
2544 * resolved in this step, however actually written in the Publish steps.
2545 * But we will leave it here for now because it is unclear
2547 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2549 WCHAR squished_pc[GUID_SIZE];
2550 WCHAR squished_cc[GUID_SIZE];
2551 UINT rc;
2552 MSICOMPONENT *comp;
2553 HKEY hkey=0,hkey2=0;
2555 /* writes the Component and Features values to the registry */
2557 rc = MSIREG_OpenComponents(&hkey);
2558 if (rc != ERROR_SUCCESS)
2559 return rc;
2561 squash_guid(package->ProductCode,squished_pc);
2562 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2564 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2566 MSIRECORD * uirow;
2568 ui_progress(package,2,0,0,0);
2569 if (!comp->ComponentId)
2570 continue;
2572 squash_guid(comp->ComponentId,squished_cc);
2574 msi_free(comp->FullKeypath);
2575 comp->FullKeypath = resolve_keypath( package, comp );
2577 /* do the refcounting */
2578 ACTION_RefCountComponent( package, comp );
2580 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2581 debugstr_w(comp->Component),
2582 debugstr_w(squished_cc),
2583 debugstr_w(comp->FullKeypath),
2584 comp->RefCount);
2586 * Write the keypath out if the component is to be registered
2587 * and delete the key if the component is to be deregistered
2589 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2591 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2592 if (rc != ERROR_SUCCESS)
2593 continue;
2595 if (!comp->FullKeypath)
2596 continue;
2598 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2600 if (comp->Attributes & msidbComponentAttributesPermanent)
2602 static const WCHAR szPermKey[] =
2603 { '0','0','0','0','0','0','0','0','0','0','0','0',
2604 '0','0','0','0','0','0','0','0','0','0','0','0',
2605 '0','0','0','0','0','0','0','0',0 };
2607 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2610 RegCloseKey(hkey2);
2612 /* UI stuff */
2613 uirow = MSI_CreateRecord(3);
2614 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2615 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2616 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2617 ui_actiondata(package,szProcessComponents,uirow);
2618 msiobj_release( &uirow->hdr );
2620 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2622 DWORD res;
2624 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2625 if (rc != ERROR_SUCCESS)
2626 continue;
2628 RegDeleteValueW(hkey2,squished_pc);
2630 /* if the key is empty delete it */
2631 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2632 RegCloseKey(hkey2);
2633 if (res == ERROR_NO_MORE_ITEMS)
2634 RegDeleteKeyW(hkey,squished_cc);
2636 /* UI stuff */
2637 uirow = MSI_CreateRecord(2);
2638 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2639 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2640 ui_actiondata(package,szProcessComponents,uirow);
2641 msiobj_release( &uirow->hdr );
2644 RegCloseKey(hkey);
2645 return rc;
2648 typedef struct {
2649 CLSID clsid;
2650 LPWSTR source;
2652 LPWSTR path;
2653 ITypeLib *ptLib;
2654 } typelib_struct;
2656 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2657 LPWSTR lpszName, LONG_PTR lParam)
2659 TLIBATTR *attr;
2660 typelib_struct *tl_struct = (typelib_struct*) lParam;
2661 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2662 int sz;
2663 HRESULT res;
2665 if (!IS_INTRESOURCE(lpszName))
2667 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2668 return TRUE;
2671 sz = strlenW(tl_struct->source)+4;
2672 sz *= sizeof(WCHAR);
2674 if ((INT_PTR)lpszName == 1)
2675 tl_struct->path = strdupW(tl_struct->source);
2676 else
2678 tl_struct->path = msi_alloc(sz);
2679 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2682 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2683 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2684 if (!SUCCEEDED(res))
2686 msi_free(tl_struct->path);
2687 tl_struct->path = NULL;
2689 return TRUE;
2692 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2693 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2695 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2696 return FALSE;
2699 msi_free(tl_struct->path);
2700 tl_struct->path = NULL;
2702 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2703 ITypeLib_Release(tl_struct->ptLib);
2705 return TRUE;
2708 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2710 MSIPACKAGE* package = (MSIPACKAGE*)param;
2711 LPCWSTR component;
2712 MSICOMPONENT *comp;
2713 MSIFILE *file;
2714 typelib_struct tl_struct;
2715 HMODULE module;
2716 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2718 component = MSI_RecordGetString(row,3);
2719 comp = get_loaded_component(package,component);
2720 if (!comp)
2721 return ERROR_SUCCESS;
2723 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2725 TRACE("Skipping typelib reg due to disabled component\n");
2727 comp->Action = comp->Installed;
2729 return ERROR_SUCCESS;
2732 comp->Action = INSTALLSTATE_LOCAL;
2734 file = get_loaded_file( package, comp->KeyPath );
2735 if (!file)
2736 return ERROR_SUCCESS;
2738 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2739 if (module)
2741 LPCWSTR guid;
2742 guid = MSI_RecordGetString(row,1);
2743 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2744 tl_struct.source = strdupW( file->TargetPath );
2745 tl_struct.path = NULL;
2747 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2748 (LONG_PTR)&tl_struct);
2750 if (tl_struct.path)
2752 LPWSTR help = NULL;
2753 LPCWSTR helpid;
2754 HRESULT res;
2756 helpid = MSI_RecordGetString(row,6);
2758 if (helpid)
2759 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2760 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2761 msi_free(help);
2763 if (!SUCCEEDED(res))
2764 ERR("Failed to register type library %s\n",
2765 debugstr_w(tl_struct.path));
2766 else
2768 ui_actiondata(package,szRegisterTypeLibraries,row);
2770 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2773 ITypeLib_Release(tl_struct.ptLib);
2774 msi_free(tl_struct.path);
2776 else
2777 ERR("Failed to load type library %s\n",
2778 debugstr_w(tl_struct.source));
2780 FreeLibrary(module);
2781 msi_free(tl_struct.source);
2783 else
2784 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2786 return ERROR_SUCCESS;
2789 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2792 * OK this is a bit confusing.. I am given a _Component key and I believe
2793 * that the file that is being registered as a type library is the "key file
2794 * of that component" which I interpret to mean "The file in the KeyPath of
2795 * that component".
2797 UINT rc;
2798 MSIQUERY * view;
2799 static const WCHAR Query[] =
2800 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2801 '`','T','y','p','e','L','i','b','`',0};
2803 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2804 if (rc != ERROR_SUCCESS)
2805 return ERROR_SUCCESS;
2807 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2808 msiobj_release(&view->hdr);
2809 return rc;
2812 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2814 MSIPACKAGE *package = (MSIPACKAGE*)param;
2815 LPWSTR target_file, target_folder, filename;
2816 LPCWSTR buffer, extension;
2817 MSICOMPONENT *comp;
2818 static const WCHAR szlnk[]={'.','l','n','k',0};
2819 IShellLinkW *sl = NULL;
2820 IPersistFile *pf = NULL;
2821 HRESULT res;
2823 buffer = MSI_RecordGetString(row,4);
2824 comp = get_loaded_component(package,buffer);
2825 if (!comp)
2826 return ERROR_SUCCESS;
2828 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2830 TRACE("Skipping shortcut creation due to disabled component\n");
2832 comp->Action = comp->Installed;
2834 return ERROR_SUCCESS;
2837 comp->Action = INSTALLSTATE_LOCAL;
2839 ui_actiondata(package,szCreateShortcuts,row);
2841 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2842 &IID_IShellLinkW, (LPVOID *) &sl );
2844 if (FAILED( res ))
2846 ERR("CLSID_ShellLink not available\n");
2847 goto err;
2850 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2851 if (FAILED( res ))
2853 ERR("QueryInterface(IID_IPersistFile) failed\n");
2854 goto err;
2857 buffer = MSI_RecordGetString(row,2);
2858 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2860 /* may be needed because of a bug somehwere else */
2861 create_full_pathW(target_folder);
2863 filename = msi_dup_record_field( row, 3 );
2864 reduce_to_longfilename(filename);
2866 extension = strchrW(filename,'.');
2867 if (!extension || strcmpiW(extension,szlnk))
2869 int len = strlenW(filename);
2870 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2871 memcpy(filename + len, szlnk, sizeof(szlnk));
2873 target_file = build_directory_name(2, target_folder, filename);
2874 msi_free(target_folder);
2875 msi_free(filename);
2877 buffer = MSI_RecordGetString(row,5);
2878 if (strchrW(buffer,'['))
2880 LPWSTR deformated;
2881 deformat_string(package,buffer,&deformated);
2882 IShellLinkW_SetPath(sl,deformated);
2883 msi_free(deformated);
2885 else
2887 FIXME("poorly handled shortcut format, advertised shortcut\n");
2888 IShellLinkW_SetPath(sl,comp->FullKeypath);
2891 if (!MSI_RecordIsNull(row,6))
2893 LPWSTR deformated;
2894 buffer = MSI_RecordGetString(row,6);
2895 deformat_string(package,buffer,&deformated);
2896 IShellLinkW_SetArguments(sl,deformated);
2897 msi_free(deformated);
2900 if (!MSI_RecordIsNull(row,7))
2902 buffer = MSI_RecordGetString(row,7);
2903 IShellLinkW_SetDescription(sl,buffer);
2906 if (!MSI_RecordIsNull(row,8))
2907 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2909 if (!MSI_RecordIsNull(row,9))
2911 LPWSTR Path;
2912 INT index;
2914 buffer = MSI_RecordGetString(row,9);
2916 Path = build_icon_path(package,buffer);
2917 index = MSI_RecordGetInteger(row,10);
2919 IShellLinkW_SetIconLocation(sl,Path,index);
2920 msi_free(Path);
2923 if (!MSI_RecordIsNull(row,11))
2924 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2926 if (!MSI_RecordIsNull(row,12))
2928 LPWSTR Path;
2929 buffer = MSI_RecordGetString(row,12);
2930 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2931 IShellLinkW_SetWorkingDirectory(sl,Path);
2932 msi_free(Path);
2935 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2936 IPersistFile_Save(pf,target_file,FALSE);
2938 msi_free(target_file);
2940 err:
2941 if (pf)
2942 IPersistFile_Release( pf );
2943 if (sl)
2944 IShellLinkW_Release( sl );
2946 return ERROR_SUCCESS;
2949 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2951 UINT rc;
2952 HRESULT res;
2953 MSIQUERY * view;
2954 static const WCHAR Query[] =
2955 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2956 '`','S','h','o','r','t','c','u','t','`',0};
2958 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2959 if (rc != ERROR_SUCCESS)
2960 return ERROR_SUCCESS;
2962 res = CoInitialize( NULL );
2963 if (FAILED (res))
2965 ERR("CoInitialize failed\n");
2966 return ERROR_FUNCTION_FAILED;
2969 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2970 msiobj_release(&view->hdr);
2972 CoUninitialize();
2974 return rc;
2977 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2979 MSIPACKAGE* package = (MSIPACKAGE*)param;
2980 HANDLE the_file;
2981 LPWSTR FilePath;
2982 LPCWSTR FileName;
2983 CHAR buffer[1024];
2984 DWORD sz;
2985 UINT rc;
2986 MSIRECORD *uirow;
2988 FileName = MSI_RecordGetString(row,1);
2989 if (!FileName)
2991 ERR("Unable to get FileName\n");
2992 return ERROR_SUCCESS;
2995 FilePath = build_icon_path(package,FileName);
2997 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2999 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3000 FILE_ATTRIBUTE_NORMAL, NULL);
3002 if (the_file == INVALID_HANDLE_VALUE)
3004 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3005 msi_free(FilePath);
3006 return ERROR_SUCCESS;
3011 DWORD write;
3012 sz = 1024;
3013 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3014 if (rc != ERROR_SUCCESS)
3016 ERR("Failed to get stream\n");
3017 CloseHandle(the_file);
3018 DeleteFileW(FilePath);
3019 break;
3021 WriteFile(the_file,buffer,sz,&write,NULL);
3022 } while (sz == 1024);
3024 msi_free(FilePath);
3026 CloseHandle(the_file);
3028 uirow = MSI_CreateRecord(1);
3029 MSI_RecordSetStringW(uirow,1,FileName);
3030 ui_actiondata(package,szPublishProduct,uirow);
3031 msiobj_release( &uirow->hdr );
3033 return ERROR_SUCCESS;
3037 * 99% of the work done here is only done for
3038 * advertised installs. However this is where the
3039 * Icon table is processed and written out
3040 * so that is what I am going to do here.
3042 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3044 UINT rc;
3045 MSIQUERY * view;
3046 static const WCHAR Query[]=
3047 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3048 '`','I','c','o','n','`',0};
3049 /* for registry stuff */
3050 HKEY hkey=0;
3051 HKEY hukey=0;
3052 static const WCHAR szProductLanguage[] =
3053 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3054 static const WCHAR szARPProductIcon[] =
3055 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3056 static const WCHAR szProductVersion[] =
3057 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3058 DWORD langid;
3059 LPWSTR buffer;
3060 DWORD size;
3061 MSIHANDLE hDb, hSumInfo;
3063 /* write out icon files */
3065 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3066 if (rc == ERROR_SUCCESS)
3068 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3069 msiobj_release(&view->hdr);
3072 /* ok there is a lot more done here but i need to figure out what */
3074 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3075 if (rc != ERROR_SUCCESS)
3076 goto end;
3078 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3079 if (rc != ERROR_SUCCESS)
3080 goto end;
3083 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3084 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3085 msi_free(buffer);
3087 langid = msi_get_property_int( package, szProductLanguage, 0 );
3088 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3090 buffer = msi_dup_property( package, szARPProductIcon );
3091 if (buffer)
3093 LPWSTR path = build_icon_path(package,buffer);
3094 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3095 msi_free( path );
3097 msi_free(buffer);
3099 buffer = msi_dup_property( package, szProductVersion );
3100 if (buffer)
3102 DWORD verdword = build_version_dword(buffer);
3103 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3105 msi_free(buffer);
3107 /* FIXME: Need to write more keys to the user registry */
3109 hDb= alloc_msihandle( &package->db->hdr );
3110 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3111 MsiCloseHandle(hDb);
3112 if (rc == ERROR_SUCCESS)
3114 WCHAR guidbuffer[0x200];
3115 size = 0x200;
3116 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3117 guidbuffer, &size);
3118 if (rc == ERROR_SUCCESS)
3120 WCHAR squashed[GUID_SIZE];
3121 /* for now we only care about the first guid */
3122 LPWSTR ptr = strchrW(guidbuffer,';');
3123 if (ptr) *ptr = 0;
3124 squash_guid(guidbuffer,squashed);
3125 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3127 else
3129 ERR("Unable to query Revision_Number...\n");
3130 rc = ERROR_SUCCESS;
3132 MsiCloseHandle(hSumInfo);
3134 else
3136 ERR("Unable to open Summary Information\n");
3137 rc = ERROR_SUCCESS;
3140 end:
3142 RegCloseKey(hkey);
3143 RegCloseKey(hukey);
3145 return rc;
3148 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3150 MSIPACKAGE *package = (MSIPACKAGE*)param;
3151 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3152 LPWSTR deformated_section, deformated_key, deformated_value;
3153 LPWSTR folder, fullname = NULL;
3154 MSIRECORD * uirow;
3155 INT action;
3156 MSICOMPONENT *comp;
3157 static const WCHAR szWindowsFolder[] =
3158 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3160 component = MSI_RecordGetString(row, 8);
3161 comp = get_loaded_component(package,component);
3163 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3165 TRACE("Skipping ini file due to disabled component %s\n",
3166 debugstr_w(component));
3168 comp->Action = comp->Installed;
3170 return ERROR_SUCCESS;
3173 comp->Action = INSTALLSTATE_LOCAL;
3175 identifier = MSI_RecordGetString(row,1);
3176 filename = MSI_RecordGetString(row,2);
3177 dirproperty = MSI_RecordGetString(row,3);
3178 section = MSI_RecordGetString(row,4);
3179 key = MSI_RecordGetString(row,5);
3180 value = MSI_RecordGetString(row,6);
3181 action = MSI_RecordGetInteger(row,7);
3183 deformat_string(package,section,&deformated_section);
3184 deformat_string(package,key,&deformated_key);
3185 deformat_string(package,value,&deformated_value);
3187 if (dirproperty)
3189 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3190 if (!folder)
3191 folder = msi_dup_property( package, dirproperty );
3193 else
3194 folder = msi_dup_property( package, szWindowsFolder );
3196 if (!folder)
3198 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3199 goto cleanup;
3202 fullname = build_directory_name(2, folder, filename);
3204 if (action == 0)
3206 TRACE("Adding value %s to section %s in %s\n",
3207 debugstr_w(deformated_key), debugstr_w(deformated_section),
3208 debugstr_w(fullname));
3209 WritePrivateProfileStringW(deformated_section, deformated_key,
3210 deformated_value, fullname);
3212 else if (action == 1)
3214 WCHAR returned[10];
3215 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3216 returned, 10, fullname);
3217 if (returned[0] == 0)
3219 TRACE("Adding value %s to section %s in %s\n",
3220 debugstr_w(deformated_key), debugstr_w(deformated_section),
3221 debugstr_w(fullname));
3223 WritePrivateProfileStringW(deformated_section, deformated_key,
3224 deformated_value, fullname);
3227 else if (action == 3)
3228 FIXME("Append to existing section not yet implemented\n");
3230 uirow = MSI_CreateRecord(4);
3231 MSI_RecordSetStringW(uirow,1,identifier);
3232 MSI_RecordSetStringW(uirow,2,deformated_section);
3233 MSI_RecordSetStringW(uirow,3,deformated_key);
3234 MSI_RecordSetStringW(uirow,4,deformated_value);
3235 ui_actiondata(package,szWriteIniValues,uirow);
3236 msiobj_release( &uirow->hdr );
3237 cleanup:
3238 msi_free(fullname);
3239 msi_free(folder);
3240 msi_free(deformated_key);
3241 msi_free(deformated_value);
3242 msi_free(deformated_section);
3243 return ERROR_SUCCESS;
3246 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3248 UINT rc;
3249 MSIQUERY * view;
3250 static const WCHAR ExecSeqQuery[] =
3251 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3252 '`','I','n','i','F','i','l','e','`',0};
3254 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3255 if (rc != ERROR_SUCCESS)
3257 TRACE("no IniFile table\n");
3258 return ERROR_SUCCESS;
3261 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3262 msiobj_release(&view->hdr);
3263 return rc;
3266 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3268 MSIPACKAGE *package = (MSIPACKAGE*)param;
3269 LPCWSTR filename;
3270 LPWSTR FullName;
3271 MSIFILE *file;
3272 DWORD len;
3273 static const WCHAR ExeStr[] =
3274 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3275 static const WCHAR close[] = {'\"',0};
3276 STARTUPINFOW si;
3277 PROCESS_INFORMATION info;
3278 BOOL brc;
3279 MSIRECORD *uirow;
3280 LPWSTR uipath, p;
3282 memset(&si,0,sizeof(STARTUPINFOW));
3284 filename = MSI_RecordGetString(row,1);
3285 file = get_loaded_file( package, filename );
3287 if (!file)
3289 ERR("Unable to find file id %s\n",debugstr_w(filename));
3290 return ERROR_SUCCESS;
3293 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3295 FullName = msi_alloc(len*sizeof(WCHAR));
3296 strcpyW(FullName,ExeStr);
3297 strcatW( FullName, file->TargetPath );
3298 strcatW(FullName,close);
3300 TRACE("Registering %s\n",debugstr_w(FullName));
3301 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3302 &si, &info);
3304 if (brc)
3305 msi_dialog_check_messages(info.hProcess);
3307 msi_free(FullName);
3309 /* the UI chunk */
3310 uirow = MSI_CreateRecord( 2 );
3311 uipath = strdupW( file->TargetPath );
3312 p = strrchrW(uipath,'\\');
3313 if (p)
3314 p[1]=0;
3315 MSI_RecordSetStringW( uirow, 1, &p[2] );
3316 MSI_RecordSetStringW( uirow, 2, uipath);
3317 ui_actiondata( package, szSelfRegModules, uirow);
3318 msiobj_release( &uirow->hdr );
3319 msi_free( uipath );
3320 /* FIXME: call ui_progress? */
3322 return ERROR_SUCCESS;
3325 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3327 UINT rc;
3328 MSIQUERY * view;
3329 static const WCHAR ExecSeqQuery[] =
3330 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3331 '`','S','e','l','f','R','e','g','`',0};
3333 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3334 if (rc != ERROR_SUCCESS)
3336 TRACE("no SelfReg table\n");
3337 return ERROR_SUCCESS;
3340 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3341 msiobj_release(&view->hdr);
3343 return ERROR_SUCCESS;
3346 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3348 MSIFEATURE *feature;
3349 UINT rc;
3350 HKEY hkey=0;
3351 HKEY hukey=0;
3353 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3354 if (rc != ERROR_SUCCESS)
3355 goto end;
3357 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3358 if (rc != ERROR_SUCCESS)
3359 goto end;
3361 /* here the guids are base 85 encoded */
3362 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3364 ComponentList *cl;
3365 LPWSTR data = NULL;
3366 GUID clsid;
3367 INT size;
3368 BOOL absent = FALSE;
3369 MSIRECORD *uirow;
3371 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3372 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3373 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3374 absent = TRUE;
3376 size = 1;
3377 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3379 size += 21;
3381 if (feature->Feature_Parent)
3382 size += strlenW( feature->Feature_Parent )+2;
3384 data = msi_alloc(size * sizeof(WCHAR));
3386 data[0] = 0;
3387 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3389 MSICOMPONENT* component = cl->component;
3390 WCHAR buf[21];
3392 buf[0] = 0;
3393 if (component->ComponentId)
3395 TRACE("From %s\n",debugstr_w(component->ComponentId));
3396 CLSIDFromString(component->ComponentId, &clsid);
3397 encode_base85_guid(&clsid,buf);
3398 TRACE("to %s\n",debugstr_w(buf));
3399 strcatW(data,buf);
3402 if (feature->Feature_Parent)
3404 static const WCHAR sep[] = {'\2',0};
3405 strcatW(data,sep);
3406 strcatW(data,feature->Feature_Parent);
3409 msi_reg_set_val_str( hkey, feature->Feature, data );
3410 msi_free(data);
3412 size = 0;
3413 if (feature->Feature_Parent)
3414 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3415 if (!absent)
3417 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3418 (LPBYTE)feature->Feature_Parent,size);
3420 else
3422 size += 2*sizeof(WCHAR);
3423 data = msi_alloc(size);
3424 data[0] = 0x6;
3425 data[1] = 0;
3426 if (feature->Feature_Parent)
3427 strcpyW( &data[1], feature->Feature_Parent );
3428 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3429 (LPBYTE)data,size);
3430 msi_free(data);
3433 /* the UI chunk */
3434 uirow = MSI_CreateRecord( 1 );
3435 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3436 ui_actiondata( package, szPublishFeatures, uirow);
3437 msiobj_release( &uirow->hdr );
3438 /* FIXME: call ui_progress? */
3441 end:
3442 RegCloseKey(hkey);
3443 RegCloseKey(hukey);
3444 return rc;
3447 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3449 static const WCHAR installerPathFmt[] = {
3450 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3451 static const WCHAR fmt[] = {
3452 '%','s','\\',
3453 'I','n','s','t','a','l','l','e','r','\\',
3454 '%','x','.','m','s','i',0};
3455 static const WCHAR szOriginalDatabase[] =
3456 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3457 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3458 INT num, start;
3459 LPWSTR msiFilePath;
3460 BOOL r;
3462 /* copy the package locally */
3463 num = GetTickCount() & 0xffff;
3464 if (!num)
3465 num = 1;
3466 start = num;
3467 GetWindowsDirectoryW( windir, MAX_PATH );
3468 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3471 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3472 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3473 if (handle != INVALID_HANDLE_VALUE)
3475 CloseHandle(handle);
3476 break;
3478 if (GetLastError() != ERROR_FILE_EXISTS &&
3479 GetLastError() != ERROR_SHARING_VIOLATION)
3480 break;
3481 if (!(++num & 0xffff)) num = 1;
3482 sprintfW(packagefile,fmt,num);
3483 } while (num != start);
3485 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3486 create_full_pathW(path);
3488 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3490 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3491 r = CopyFileW( msiFilePath, packagefile, FALSE);
3492 msi_free( msiFilePath );
3494 if (!r)
3496 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3497 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3498 return ERROR_FUNCTION_FAILED;
3501 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3502 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3503 return ERROR_SUCCESS;
3506 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3508 LPWSTR prop, val, key;
3509 static const LPCSTR propval[] = {
3510 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3511 "ARPCONTACT", "Contact",
3512 "ARPCOMMENTS", "Comments",
3513 "ProductName", "DisplayName",
3514 "ProductVersion", "DisplayVersion",
3515 "ARPHELPLINK", "HelpLink",
3516 "ARPHELPTELEPHONE", "HelpTelephone",
3517 "ARPINSTALLLOCATION", "InstallLocation",
3518 "SourceDir", "InstallSource",
3519 "Manufacturer", "Publisher",
3520 "ARPREADME", "Readme",
3521 "ARPSIZE", "Size",
3522 "ARPURLINFOABOUT", "URLInfoAbout",
3523 "ARPURLUPDATEINFO", "URLUpdateInfo",
3524 NULL,
3526 const LPCSTR *p = propval;
3528 while( *p )
3530 prop = strdupAtoW( *p++ );
3531 key = strdupAtoW( *p++ );
3532 val = msi_dup_property( package, prop );
3533 msi_reg_set_val_str( hkey, key, val );
3534 msi_free(val);
3535 msi_free(key);
3536 msi_free(prop);
3538 return ERROR_SUCCESS;
3541 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3543 HKEY hkey=0;
3544 LPWSTR buffer = NULL;
3545 UINT rc;
3546 DWORD size, langid;
3547 static const WCHAR szWindowsInstaller[] =
3548 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3549 static const WCHAR szUpgradeCode[] =
3550 {'U','p','g','r','a','d','e','C','o','d','e',0};
3551 static const WCHAR modpath_fmt[] =
3552 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3553 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3554 static const WCHAR szModifyPath[] =
3555 {'M','o','d','i','f','y','P','a','t','h',0};
3556 static const WCHAR szUninstallString[] =
3557 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3558 static const WCHAR szEstimatedSize[] =
3559 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3560 static const WCHAR szProductLanguage[] =
3561 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3562 static const WCHAR szProductVersion[] =
3563 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3565 SYSTEMTIME systime;
3566 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3567 LPWSTR upgrade_code;
3568 WCHAR szDate[9];
3570 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3571 if (rc != ERROR_SUCCESS)
3572 return rc;
3574 /* dump all the info i can grab */
3575 /* FIXME: Flesh out more information */
3577 msi_write_uninstall_property_vals( package, hkey );
3579 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3581 msi_make_package_local( package, hkey );
3583 /* do ModifyPath and UninstallString */
3584 size = deformat_string(package,modpath_fmt,&buffer);
3585 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3586 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3587 msi_free(buffer);
3589 /* FIXME: Write real Estimated Size when we have it */
3590 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3592 GetLocalTime(&systime);
3593 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3594 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3596 langid = msi_get_property_int( package, szProductLanguage, 0 );
3597 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3599 buffer = msi_dup_property( package, szProductVersion );
3600 if (buffer)
3602 DWORD verdword = build_version_dword(buffer);
3604 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3605 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3606 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3608 msi_free(buffer);
3610 /* Handle Upgrade Codes */
3611 upgrade_code = msi_dup_property( package, szUpgradeCode );
3612 if (upgrade_code)
3614 HKEY hkey2;
3615 WCHAR squashed[33];
3616 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3617 squash_guid(package->ProductCode,squashed);
3618 msi_reg_set_val_str( hkey2, squashed, NULL );
3619 RegCloseKey(hkey2);
3620 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3621 squash_guid(package->ProductCode,squashed);
3622 msi_reg_set_val_str( hkey2, squashed, NULL );
3623 RegCloseKey(hkey2);
3625 msi_free(upgrade_code);
3628 RegCloseKey(hkey);
3630 /* FIXME: call ui_actiondata */
3632 return ERROR_SUCCESS;
3635 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3637 return execute_script(package,INSTALL_SCRIPT);
3640 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3642 UINT rc;
3644 /* turn off scheduleing */
3645 package->script->CurrentlyScripting= FALSE;
3647 /* first do the same as an InstallExecute */
3648 rc = ACTION_InstallExecute(package);
3649 if (rc != ERROR_SUCCESS)
3650 return rc;
3652 /* then handle Commit Actions */
3653 rc = execute_script(package,COMMIT_SCRIPT);
3655 return rc;
3658 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3660 static const WCHAR RunOnce[] = {
3661 'S','o','f','t','w','a','r','e','\\',
3662 'M','i','c','r','o','s','o','f','t','\\',
3663 'W','i','n','d','o','w','s','\\',
3664 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3665 'R','u','n','O','n','c','e',0};
3666 static const WCHAR InstallRunOnce[] = {
3667 'S','o','f','t','w','a','r','e','\\',
3668 'M','i','c','r','o','s','o','f','t','\\',
3669 'W','i','n','d','o','w','s','\\',
3670 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3671 'I','n','s','t','a','l','l','e','r','\\',
3672 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3674 static const WCHAR msiexec_fmt[] = {
3675 '%','s',
3676 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3677 '\"','%','s','\"',0};
3678 static const WCHAR install_fmt[] = {
3679 '/','I',' ','\"','%','s','\"',' ',
3680 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3681 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3682 WCHAR buffer[256], sysdir[MAX_PATH];
3683 HKEY hkey;
3684 WCHAR squished_pc[100];
3686 squash_guid(package->ProductCode,squished_pc);
3688 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3689 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3690 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3691 squished_pc);
3693 msi_reg_set_val_str( hkey, squished_pc, buffer );
3694 RegCloseKey(hkey);
3696 TRACE("Reboot command %s\n",debugstr_w(buffer));
3698 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3699 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3701 msi_reg_set_val_str( hkey, squished_pc, buffer );
3702 RegCloseKey(hkey);
3704 return ERROR_INSTALL_SUSPEND;
3707 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3709 DWORD attrib;
3710 UINT rc;
3712 * we are currently doing what should be done here in the top level Install
3713 * however for Adminastrative and uninstalls this step will be needed
3715 if (!package->PackagePath)
3716 return ERROR_SUCCESS;
3718 attrib = GetFileAttributesW(package->PackagePath);
3719 if (attrib == INVALID_FILE_ATTRIBUTES)
3721 LPWSTR prompt;
3722 LPWSTR msg;
3723 DWORD size = 0;
3725 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3726 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3727 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3728 if (rc == ERROR_MORE_DATA)
3730 prompt = msi_alloc(size * sizeof(WCHAR));
3731 MsiSourceListGetInfoW(package->ProductCode, NULL,
3732 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3733 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3735 else
3736 prompt = strdupW(package->PackagePath);
3738 msg = generate_error_string(package,1302,1,prompt);
3739 while(attrib == INVALID_FILE_ATTRIBUTES)
3741 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3742 if (rc == IDCANCEL)
3744 rc = ERROR_INSTALL_USEREXIT;
3745 break;
3747 attrib = GetFileAttributesW(package->PackagePath);
3749 msi_free(prompt);
3750 rc = ERROR_SUCCESS;
3752 else
3753 return ERROR_SUCCESS;
3755 return rc;
3758 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3760 HKEY hkey=0;
3761 LPWSTR buffer;
3762 LPWSTR productid;
3763 UINT rc,i;
3765 static const WCHAR szPropKeys[][80] =
3767 {'P','r','o','d','u','c','t','I','D',0},
3768 {'U','S','E','R','N','A','M','E',0},
3769 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3770 {0},
3773 static const WCHAR szRegKeys[][80] =
3775 {'P','r','o','d','u','c','t','I','D',0},
3776 {'R','e','g','O','w','n','e','r',0},
3777 {'R','e','g','C','o','m','p','a','n','y',0},
3778 {0},
3781 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3782 if (!productid)
3783 return ERROR_SUCCESS;
3785 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3786 if (rc != ERROR_SUCCESS)
3787 goto end;
3789 for( i = 0; szPropKeys[i][0]; i++ )
3791 buffer = msi_dup_property( package, szPropKeys[i] );
3792 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3793 msi_free( buffer );
3796 end:
3797 msi_free(productid);
3798 RegCloseKey(hkey);
3800 /* FIXME: call ui_actiondata */
3802 return ERROR_SUCCESS;
3806 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3808 UINT rc;
3810 package->script->InWhatSequence |= SEQUENCE_EXEC;
3811 rc = ACTION_ProcessExecSequence(package,FALSE);
3812 return rc;
3817 * Code based off of code located here
3818 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3820 * Using string index 4 (full font name) instead of 1 (family name)
3822 static LPWSTR load_ttfname_from(LPCWSTR filename)
3824 HANDLE handle;
3825 LPWSTR ret = NULL;
3826 int i;
3828 typedef struct _tagTT_OFFSET_TABLE{
3829 USHORT uMajorVersion;
3830 USHORT uMinorVersion;
3831 USHORT uNumOfTables;
3832 USHORT uSearchRange;
3833 USHORT uEntrySelector;
3834 USHORT uRangeShift;
3835 }TT_OFFSET_TABLE;
3837 typedef struct _tagTT_TABLE_DIRECTORY{
3838 char szTag[4]; /* table name */
3839 ULONG uCheckSum; /* Check sum */
3840 ULONG uOffset; /* Offset from beginning of file */
3841 ULONG uLength; /* length of the table in bytes */
3842 }TT_TABLE_DIRECTORY;
3844 typedef struct _tagTT_NAME_TABLE_HEADER{
3845 USHORT uFSelector; /* format selector. Always 0 */
3846 USHORT uNRCount; /* Name Records count */
3847 USHORT uStorageOffset; /* Offset for strings storage,
3848 * from start of the table */
3849 }TT_NAME_TABLE_HEADER;
3851 typedef struct _tagTT_NAME_RECORD{
3852 USHORT uPlatformID;
3853 USHORT uEncodingID;
3854 USHORT uLanguageID;
3855 USHORT uNameID;
3856 USHORT uStringLength;
3857 USHORT uStringOffset; /* from start of storage area */
3858 }TT_NAME_RECORD;
3860 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3861 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3863 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3864 FILE_ATTRIBUTE_NORMAL, 0 );
3865 if (handle != INVALID_HANDLE_VALUE)
3867 TT_TABLE_DIRECTORY tblDir;
3868 BOOL bFound = FALSE;
3869 TT_OFFSET_TABLE ttOffsetTable;
3870 DWORD dwRead;
3872 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3873 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3874 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3875 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3877 if (ttOffsetTable.uMajorVersion != 1 ||
3878 ttOffsetTable.uMinorVersion != 0)
3879 return NULL;
3881 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3883 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3884 if (strncmp(tblDir.szTag,"name",4)==0)
3886 bFound = TRUE;
3887 tblDir.uLength = SWAPLONG(tblDir.uLength);
3888 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3889 break;
3893 if (bFound)
3895 TT_NAME_TABLE_HEADER ttNTHeader;
3896 TT_NAME_RECORD ttRecord;
3898 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3899 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3900 &dwRead,NULL);
3902 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3903 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3904 bFound = FALSE;
3905 for(i=0; i<ttNTHeader.uNRCount; i++)
3907 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3908 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3909 /* 4 is the Full Font Name */
3910 if(ttRecord.uNameID == 4)
3912 int nPos;
3913 LPSTR buf;
3914 static LPCSTR tt = " (TrueType)";
3916 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3917 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3918 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3919 SetFilePointer(handle, tblDir.uOffset +
3920 ttRecord.uStringOffset +
3921 ttNTHeader.uStorageOffset,
3922 NULL, FILE_BEGIN);
3923 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3924 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3925 if (strlen(buf) > 0)
3927 strcat(buf,tt);
3928 ret = strdupAtoW(buf);
3929 msi_free(buf);
3930 break;
3933 msi_free(buf);
3934 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3938 CloseHandle(handle);
3940 else
3941 ERR("Unable to open font file %s\n", debugstr_w(filename));
3943 TRACE("Returning fontname %s\n",debugstr_w(ret));
3944 return ret;
3947 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3949 MSIPACKAGE *package = (MSIPACKAGE*)param;
3950 LPWSTR name;
3951 LPCWSTR filename;
3952 MSIFILE *file;
3953 static const WCHAR regfont1[] =
3954 {'S','o','f','t','w','a','r','e','\\',
3955 'M','i','c','r','o','s','o','f','t','\\',
3956 'W','i','n','d','o','w','s',' ','N','T','\\',
3957 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3958 'F','o','n','t','s',0};
3959 static const WCHAR regfont2[] =
3960 {'S','o','f','t','w','a','r','e','\\',
3961 'M','i','c','r','o','s','o','f','t','\\',
3962 'W','i','n','d','o','w','s','\\',
3963 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3964 'F','o','n','t','s',0};
3965 HKEY hkey1;
3966 HKEY hkey2;
3967 MSIRECORD *uirow;
3968 LPWSTR uipath, p;
3970 filename = MSI_RecordGetString( row, 1 );
3971 file = get_loaded_file( package, filename );
3972 if (!file)
3974 ERR("Unable to load file\n");
3975 return ERROR_SUCCESS;
3978 /* check to make sure that component is installed */
3979 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3981 TRACE("Skipping: Component not scheduled for install\n");
3982 return ERROR_SUCCESS;
3985 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3986 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3988 if (MSI_RecordIsNull(row,2))
3989 name = load_ttfname_from( file->TargetPath );
3990 else
3991 name = msi_dup_record_field(row,2);
3993 if (name)
3995 msi_reg_set_val_str( hkey1, name, file->FileName );
3996 msi_reg_set_val_str( hkey2, name, file->FileName );
3999 msi_free(name);
4000 RegCloseKey(hkey1);
4001 RegCloseKey(hkey2);
4003 /* the UI chunk */
4004 uirow = MSI_CreateRecord( 1 );
4005 uipath = strdupW( file->TargetPath );
4006 p = strrchrW(uipath,'\\');
4007 if (p) p++;
4008 else p = uipath;
4009 MSI_RecordSetStringW( uirow, 1, p );
4010 ui_actiondata( package, szRegisterFonts, uirow);
4011 msiobj_release( &uirow->hdr );
4012 msi_free( uipath );
4013 /* FIXME: call ui_progress? */
4015 return ERROR_SUCCESS;
4018 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4020 UINT rc;
4021 MSIQUERY * view;
4022 static const WCHAR ExecSeqQuery[] =
4023 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4024 '`','F','o','n','t','`',0};
4026 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4027 if (rc != ERROR_SUCCESS)
4029 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4030 return ERROR_SUCCESS;
4033 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4034 msiobj_release(&view->hdr);
4036 return ERROR_SUCCESS;
4039 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4041 MSIPACKAGE *package = (MSIPACKAGE*)param;
4042 LPCWSTR compgroupid=NULL;
4043 LPCWSTR feature=NULL;
4044 LPCWSTR text = NULL;
4045 LPCWSTR qualifier = NULL;
4046 LPCWSTR component = NULL;
4047 LPWSTR advertise = NULL;
4048 LPWSTR output = NULL;
4049 HKEY hkey;
4050 UINT rc = ERROR_SUCCESS;
4051 MSICOMPONENT *comp;
4052 DWORD sz = 0;
4053 MSIRECORD *uirow;
4055 component = MSI_RecordGetString(rec,3);
4056 comp = get_loaded_component(package,component);
4058 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4059 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4060 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4062 TRACE("Skipping: Component %s not scheduled for install\n",
4063 debugstr_w(component));
4065 return ERROR_SUCCESS;
4068 compgroupid = MSI_RecordGetString(rec,1);
4069 qualifier = MSI_RecordGetString(rec,2);
4071 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4072 if (rc != ERROR_SUCCESS)
4073 goto end;
4075 text = MSI_RecordGetString(rec,4);
4076 feature = MSI_RecordGetString(rec,5);
4078 advertise = create_component_advertise_string(package, comp, feature);
4080 sz = strlenW(advertise);
4082 if (text)
4083 sz += lstrlenW(text);
4085 sz+=3;
4086 sz *= sizeof(WCHAR);
4088 output = msi_alloc_zero(sz);
4089 strcpyW(output,advertise);
4090 msi_free(advertise);
4092 if (text)
4093 strcatW(output,text);
4095 msi_reg_set_val_multi_str( hkey, qualifier, output );
4097 end:
4098 RegCloseKey(hkey);
4099 msi_free(output);
4101 /* the UI chunk */
4102 uirow = MSI_CreateRecord( 2 );
4103 MSI_RecordSetStringW( uirow, 1, compgroupid );
4104 MSI_RecordSetStringW( uirow, 2, qualifier);
4105 ui_actiondata( package, szPublishComponents, uirow);
4106 msiobj_release( &uirow->hdr );
4107 /* FIXME: call ui_progress? */
4109 return rc;
4113 * At present I am ignorning the advertised components part of this and only
4114 * focusing on the qualified component sets
4116 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4118 UINT rc;
4119 MSIQUERY * view;
4120 static const WCHAR ExecSeqQuery[] =
4121 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4122 '`','P','u','b','l','i','s','h',
4123 'C','o','m','p','o','n','e','n','t','`',0};
4125 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4126 if (rc != ERROR_SUCCESS)
4127 return ERROR_SUCCESS;
4129 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4130 msiobj_release(&view->hdr);
4132 return rc;
4135 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4136 LPCSTR action, LPCWSTR table )
4138 static const WCHAR query[] = {
4139 'S','E','L','E','C','T',' ','*',' ',
4140 'F','R','O','M',' ','`','%','s','`',0 };
4141 MSIQUERY *view = NULL;
4142 DWORD count = 0;
4143 UINT r;
4145 r = MSI_OpenQuery( package->db, &view, query, table );
4146 if (r == ERROR_SUCCESS)
4148 r = MSI_IterateRecords(view, &count, NULL, package);
4149 msiobj_release(&view->hdr);
4152 if (count)
4153 FIXME("%s -> %lu ignored %s table values\n",
4154 action, count, debugstr_w(table));
4156 return ERROR_SUCCESS;
4159 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4161 TRACE("%p\n", package);
4162 return ERROR_SUCCESS;
4165 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4167 static const WCHAR table[] =
4168 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4169 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4172 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4174 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4175 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4178 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4180 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4181 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4184 static UINT ACTION_BindImage( MSIPACKAGE *package )
4186 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4187 return msi_unimplemented_action_stub( package, "BindImage", table );
4190 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4192 static const WCHAR table[] = {
4193 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4194 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4197 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4199 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4200 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4203 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4205 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4206 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4209 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4211 static const WCHAR table[] = {
4212 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4213 return msi_unimplemented_action_stub( package, "InstallServices", table );
4216 static UINT ACTION_StartServices( MSIPACKAGE *package )
4218 static const WCHAR table[] = {
4219 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4220 return msi_unimplemented_action_stub( package, "StartServices", table );
4223 static UINT ACTION_StopServices( MSIPACKAGE *package )
4225 static const WCHAR table[] = {
4226 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4227 return msi_unimplemented_action_stub( package, "StopServices", table );
4230 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4232 static const WCHAR table[] = {
4233 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4234 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4237 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4239 static const WCHAR table[] = {
4240 'E','n','v','i','r','o','n','m','e','n','t',0 };
4241 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4244 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4246 static const WCHAR table[] = {
4247 'E','n','v','i','r','o','n','m','e','n','t',0 };
4248 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4251 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4253 static const WCHAR table[] = {
4254 'M','s','i','A','s','s','e','m','b','l','y',0 };
4255 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4258 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4260 static const WCHAR table[] = {
4261 'M','s','i','A','s','s','e','m','b','l','y',0 };
4262 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4265 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4267 static const WCHAR table[] = { 'F','o','n','t',0 };
4268 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4271 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4273 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4274 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4277 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4279 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4280 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4283 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4285 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4286 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4289 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4291 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4292 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4295 static struct _actions StandardActions[] = {
4296 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4297 { szAppSearch, ACTION_AppSearch },
4298 { szBindImage, ACTION_BindImage },
4299 { szCCPSearch, ACTION_CCPSearch},
4300 { szCostFinalize, ACTION_CostFinalize },
4301 { szCostInitialize, ACTION_CostInitialize },
4302 { szCreateFolders, ACTION_CreateFolders },
4303 { szCreateShortcuts, ACTION_CreateShortcuts },
4304 { szDeleteServices, ACTION_DeleteServices },
4305 { szDisableRollback, NULL},
4306 { szDuplicateFiles, ACTION_DuplicateFiles },
4307 { szExecuteAction, ACTION_ExecuteAction },
4308 { szFileCost, ACTION_FileCost },
4309 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4310 { szForceReboot, ACTION_ForceReboot },
4311 { szInstallAdminPackage, NULL},
4312 { szInstallExecute, ACTION_InstallExecute },
4313 { szInstallExecuteAgain, ACTION_InstallExecute },
4314 { szInstallFiles, ACTION_InstallFiles},
4315 { szInstallFinalize, ACTION_InstallFinalize },
4316 { szInstallInitialize, ACTION_InstallInitialize },
4317 { szInstallSFPCatalogFile, NULL},
4318 { szInstallValidate, ACTION_InstallValidate },
4319 { szIsolateComponents, ACTION_IsolateComponents },
4320 { szLaunchConditions, ACTION_LaunchConditions },
4321 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4322 { szMoveFiles, ACTION_MoveFiles },
4323 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4324 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4325 { szInstallODBC, NULL},
4326 { szInstallServices, ACTION_InstallServices },
4327 { szPatchFiles, ACTION_PatchFiles },
4328 { szProcessComponents, ACTION_ProcessComponents },
4329 { szPublishComponents, ACTION_PublishComponents },
4330 { szPublishFeatures, ACTION_PublishFeatures },
4331 { szPublishProduct, ACTION_PublishProduct },
4332 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4333 { szRegisterComPlus, ACTION_RegisterComPlus},
4334 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4335 { szRegisterFonts, ACTION_RegisterFonts },
4336 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4337 { szRegisterProduct, ACTION_RegisterProduct },
4338 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4339 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4340 { szRegisterUser, ACTION_RegisterUser},
4341 { szRemoveDuplicateFiles, NULL},
4342 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4343 { szRemoveExistingProducts, NULL},
4344 { szRemoveFiles, ACTION_RemoveFiles},
4345 { szRemoveFolders, NULL},
4346 { szRemoveIniValues, ACTION_RemoveIniValues },
4347 { szRemoveODBC, NULL},
4348 { szRemoveRegistryValues, NULL},
4349 { szRemoveShortcuts, NULL},
4350 { szResolveSource, ACTION_ResolveSource},
4351 { szRMCCPSearch, ACTION_RMCCPSearch},
4352 { szScheduleReboot, NULL},
4353 { szSelfRegModules, ACTION_SelfRegModules },
4354 { szSelfUnregModules, ACTION_SelfUnregModules },
4355 { szSetODBCFolders, NULL},
4356 { szStartServices, ACTION_StartServices },
4357 { szStopServices, ACTION_StopServices },
4358 { szUnpublishComponents, NULL},
4359 { szUnpublishFeatures, NULL},
4360 { szUnregisterClassInfo, NULL},
4361 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4362 { szUnregisterExtensionInfo, NULL},
4363 { szUnregisterFonts, ACTION_UnregisterFonts },
4364 { szUnregisterMIMEInfo, NULL},
4365 { szUnregisterProgIdInfo, NULL},
4366 { szUnregisterTypeLibraries, NULL},
4367 { szValidateProductID, NULL},
4368 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4369 { szWriteIniValues, ACTION_WriteIniValues },
4370 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4371 { NULL, NULL},