msvideo: Renamed the msvideo directory to msvfw32.
[wine/testsucceed.git] / dlls / msi / action.c
blob60907a96e48b026859db24ff0a3daf5d2cbed7e8
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
31 #define COBJMACROS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "wine/debug.h"
38 #include "msidefs.h"
39 #include "msipriv.h"
40 #include "winuser.h"
41 #include "shlobj.h"
42 #include "wine/unicode.h"
43 #include "winver.h"
44 #include "action.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 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(sizeof(MSISCRIPT));
577 memset(package->script,0,sizeof(MSISCRIPT));
579 package->script->InWhatSequence = SEQUENCE_INSTALL;
581 if (szPackagePath)
583 LPWSTR p, check, path;
585 package->PackagePath = strdupW(szPackagePath);
586 path = strdupW(szPackagePath);
587 p = strrchrW(path,'\\');
588 if (p)
590 p++;
591 *p=0;
593 else
595 msi_free(path);
596 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
597 GetCurrentDirectoryW(MAX_PATH,path);
598 strcatW(path,cszbs);
601 check = msi_dup_property( package, cszSourceDir );
602 if (!check)
603 MSI_SetPropertyW(package, cszSourceDir, path);
604 msi_free(check);
605 msi_free(path);
608 msi_parse_command_line( package, szCommandLine );
610 msi_apply_transforms( package );
611 msi_apply_patches( package );
613 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
615 package->script->InWhatSequence |= SEQUENCE_UI;
616 rc = ACTION_ProcessUISequence(package);
617 ui = TRUE;
618 if (rc == ERROR_SUCCESS)
620 package->script->InWhatSequence |= SEQUENCE_EXEC;
621 rc = ACTION_ProcessExecSequence(package,TRUE);
624 else
625 rc = ACTION_ProcessExecSequence(package,FALSE);
627 if (rc == -1)
629 /* install was halted but should be considered a success */
630 rc = ERROR_SUCCESS;
633 package->script->CurrentlyScripting= FALSE;
635 /* process the ending type action */
636 if (rc == ERROR_SUCCESS)
637 ACTION_PerformActionSequence(package,-1,ui);
638 else if (rc == ERROR_INSTALL_USEREXIT)
639 ACTION_PerformActionSequence(package,-2,ui);
640 else if (rc == ERROR_INSTALL_SUSPEND)
641 ACTION_PerformActionSequence(package,-4,ui);
642 else /* failed */
643 ACTION_PerformActionSequence(package,-3,ui);
645 /* finish up running custom actions */
646 ACTION_FinishCustomActions(package);
648 return rc;
651 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
653 UINT rc = ERROR_SUCCESS;
654 MSIRECORD * row = 0;
655 static const WCHAR ExecSeqQuery[] =
656 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
657 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
658 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
659 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
661 static const WCHAR UISeqQuery[] =
662 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
663 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
664 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
665 ' ', '=',' ','%','i',0};
667 if (UI)
668 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
669 else
670 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
672 if (row)
674 LPCWSTR action, cond;
676 TRACE("Running the actions\n");
678 /* check conditions */
679 cond = MSI_RecordGetString(row,2);
680 if (cond)
682 /* this is a hack to skip errors in the condition code */
683 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
684 goto end;
687 action = MSI_RecordGetString(row,1);
688 if (!action)
690 ERR("failed to fetch action\n");
691 rc = ERROR_FUNCTION_FAILED;
692 goto end;
695 if (UI)
696 rc = ACTION_PerformUIAction(package,action);
697 else
698 rc = ACTION_PerformAction(package,action,FALSE);
699 end:
700 msiobj_release(&row->hdr);
702 else
703 rc = ERROR_SUCCESS;
705 return rc;
708 typedef struct {
709 MSIPACKAGE* package;
710 BOOL UI;
711 } iterate_action_param;
713 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
715 iterate_action_param *iap= (iterate_action_param*)param;
716 UINT rc;
717 LPCWSTR cond, action;
719 action = MSI_RecordGetString(row,1);
720 if (!action)
722 ERR("Error is retrieving action name\n");
723 return ERROR_FUNCTION_FAILED;
726 /* check conditions */
727 cond = MSI_RecordGetString(row,2);
728 if (cond)
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
733 TRACE("Skipping action: %s (condition is false)\n",
734 debugstr_w(action));
735 return ERROR_SUCCESS;
739 if (iap->UI)
740 rc = ACTION_PerformUIAction(iap->package,action);
741 else
742 rc = ACTION_PerformAction(iap->package,action,FALSE);
744 msi_dialog_check_messages( NULL );
746 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
747 rc = iap->package->CurrentInstallState;
749 if (rc == ERROR_FUNCTION_NOT_CALLED)
750 rc = ERROR_SUCCESS;
752 if (rc != ERROR_SUCCESS)
753 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
755 return rc;
758 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
760 MSIQUERY * view;
761 UINT r;
762 static const WCHAR query[] =
763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
764 '`','%','s','`',
765 ' ','W','H','E','R','E',' ',
766 '`','S','e','q','u','e','n','c','e','`',' ',
767 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
768 '`','S','e','q','u','e','n','c','e','`',0};
769 iterate_action_param iap;
772 * FIXME: probably should be checking UILevel in the
773 * ACTION_PerformUIAction/ACTION_PerformAction
774 * rather than saving the UI level here. Those
775 * two functions can be merged too.
777 iap.package = package;
778 iap.UI = TRUE;
780 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
782 r = MSI_OpenQuery( package->db, &view, query, szTable );
783 if (r == ERROR_SUCCESS)
785 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
786 msiobj_release(&view->hdr);
789 return r;
792 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
794 MSIQUERY * view;
795 UINT rc;
796 static const WCHAR ExecSeqQuery[] =
797 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
798 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
799 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
800 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
801 'O','R','D','E','R',' ', 'B','Y',' ',
802 '`','S','e','q','u','e','n','c','e','`',0 };
803 MSIRECORD * row = 0;
804 static const WCHAR IVQuery[] =
805 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
806 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
807 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
808 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
809 ' ','\'', 'I','n','s','t','a','l','l',
810 'V','a','l','i','d','a','t','e','\'', 0};
811 INT seq = 0;
812 iterate_action_param iap;
814 iap.package = package;
815 iap.UI = FALSE;
817 if (package->script->ExecuteSequenceRun)
819 TRACE("Execute Sequence already Run\n");
820 return ERROR_SUCCESS;
823 package->script->ExecuteSequenceRun = TRUE;
825 /* get the sequence number */
826 if (UIran)
828 row = MSI_QueryGetRecord(package->db, IVQuery);
829 if( !row )
830 return ERROR_FUNCTION_FAILED;
831 seq = MSI_RecordGetInteger(row,1);
832 msiobj_release(&row->hdr);
835 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
836 if (rc == ERROR_SUCCESS)
838 TRACE("Running the actions\n");
840 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
841 msiobj_release(&view->hdr);
844 return rc;
847 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
849 MSIQUERY * view;
850 UINT rc;
851 static const WCHAR ExecSeqQuery [] =
852 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
853 '`','I','n','s','t','a','l','l',
854 'U','I','S','e','q','u','e','n','c','e','`',
855 ' ','W','H','E','R','E',' ',
856 '`','S','e','q','u','e','n','c','e','`',' ',
857 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
858 '`','S','e','q','u','e','n','c','e','`',0};
859 iterate_action_param iap;
861 iap.package = package;
862 iap.UI = TRUE;
864 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
866 if (rc == ERROR_SUCCESS)
868 TRACE("Running the actions\n");
870 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
871 msiobj_release(&view->hdr);
874 return rc;
877 /********************************************************
878 * ACTION helper functions and functions that perform the actions
879 *******************************************************/
880 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
881 UINT* rc, BOOL force )
883 BOOL ret = FALSE;
884 BOOL run = force;
885 int i;
887 if (!package)
889 ERR("package was null!\n");
890 return FALSE;
893 if (!run && !package->script->CurrentlyScripting)
894 run = TRUE;
896 if (!run)
898 if (strcmpW(action,szInstallFinalize) == 0 ||
899 strcmpW(action,szInstallExecute) == 0 ||
900 strcmpW(action,szInstallExecuteAgain) == 0)
901 run = TRUE;
904 i = 0;
905 while (StandardActions[i].action != NULL)
907 if (strcmpW(StandardActions[i].action, action)==0)
909 if (!run)
911 ui_actioninfo(package, action, TRUE, 0);
912 *rc = schedule_action(package,INSTALL_SCRIPT,action);
913 ui_actioninfo(package, action, FALSE, *rc);
915 else
917 ui_actionstart(package, action);
918 if (StandardActions[i].handler)
920 *rc = StandardActions[i].handler(package);
922 else
924 FIXME("unhandled standard action %s\n",debugstr_w(action));
925 *rc = ERROR_SUCCESS;
928 ret = TRUE;
929 break;
931 i++;
933 return ret;
936 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
937 UINT* rc, BOOL force )
939 BOOL ret=FALSE;
940 UINT arc;
942 arc = ACTION_CustomAction(package,action, force);
944 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
946 *rc = arc;
947 ret = TRUE;
949 return ret;
953 * A lot of actions are really important even if they don't do anything
954 * explicit... Lots of properties are set at the beginning of the installation
955 * CostFinalize does a bunch of work to translate the directories and such
957 * But until I get write access to the database that is hard, so I am going to
958 * hack it to see if I can get something to run.
960 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
962 UINT rc = ERROR_SUCCESS;
963 BOOL handled;
965 TRACE("Performing action (%s)\n",debugstr_w(action));
967 handled = ACTION_HandleStandardAction(package, action, &rc, force);
969 if (!handled)
970 handled = ACTION_HandleCustomAction(package, action, &rc, force);
972 if (!handled)
974 FIXME("unhandled msi action %s\n",debugstr_w(action));
975 rc = ERROR_FUNCTION_NOT_CALLED;
978 return rc;
981 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
983 UINT rc = ERROR_SUCCESS;
984 BOOL handled = FALSE;
986 TRACE("Performing action (%s)\n",debugstr_w(action));
988 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
990 if (!handled)
991 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
993 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
994 handled = TRUE;
996 if (!handled)
998 FIXME("unhandled msi action %s\n",debugstr_w(action));
999 rc = ERROR_FUNCTION_NOT_CALLED;
1002 return rc;
1007 * Actual Action Handlers
1010 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1012 MSIPACKAGE *package = (MSIPACKAGE*)param;
1013 LPCWSTR dir;
1014 LPWSTR full_path;
1015 MSIRECORD *uirow;
1016 MSIFOLDER *folder;
1018 dir = MSI_RecordGetString(row,1);
1019 if (!dir)
1021 ERR("Unable to get folder id\n");
1022 return ERROR_SUCCESS;
1025 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1026 if (!full_path)
1028 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1029 return ERROR_SUCCESS;
1032 TRACE("Folder is %s\n",debugstr_w(full_path));
1034 /* UI stuff */
1035 uirow = MSI_CreateRecord(1);
1036 MSI_RecordSetStringW(uirow,1,full_path);
1037 ui_actiondata(package,szCreateFolders,uirow);
1038 msiobj_release( &uirow->hdr );
1040 if (folder->State == 0)
1041 create_full_pathW(full_path);
1043 folder->State = 3;
1045 msi_free(full_path);
1046 return ERROR_SUCCESS;
1049 /* FIXME: probably should merge this with the above function */
1050 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1052 UINT rc = ERROR_SUCCESS;
1053 MSIFOLDER *folder;
1054 LPWSTR install_path;
1056 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1057 if (!install_path)
1058 return ERROR_FUNCTION_FAILED;
1060 /* create the path */
1061 if (folder->State == 0)
1063 create_full_pathW(install_path);
1064 folder->State = 2;
1066 msi_free(install_path);
1068 return rc;
1071 UINT msi_create_component_directories( MSIPACKAGE *package )
1073 MSICOMPONENT *comp;
1075 /* create all the folders required by the components are going to install */
1076 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1078 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1079 continue;
1080 msi_create_directory( package, comp->Directory );
1083 return ERROR_SUCCESS;
1087 * Also we cannot enable/disable components either, so for now I am just going
1088 * to do all the directories for all the components.
1090 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1092 static const WCHAR ExecSeqQuery[] =
1093 {'S','E','L','E','C','T',' ',
1094 '`','D','i','r','e','c','t','o','r','y','_','`',
1095 ' ','F','R','O','M',' ',
1096 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1097 UINT rc;
1098 MSIQUERY *view;
1100 /* create all the empty folders specified in the CreateFolder table */
1101 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1102 if (rc != ERROR_SUCCESS)
1103 return ERROR_SUCCESS;
1105 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1106 msiobj_release(&view->hdr);
1108 msi_create_component_directories( package );
1110 return rc;
1113 static MSICOMPONENT* load_component( MSIRECORD * row )
1115 MSICOMPONENT *comp;
1117 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1118 if (!comp)
1119 return comp;
1121 /* fill in the data */
1122 comp->Component = msi_dup_record_field( row, 1 );
1124 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1126 comp->ComponentId = msi_dup_record_field( row, 2 );
1127 comp->Directory = msi_dup_record_field( row, 3 );
1128 comp->Attributes = MSI_RecordGetInteger(row,4);
1129 comp->Condition = msi_dup_record_field( row, 5 );
1130 comp->KeyPath = msi_dup_record_field( row, 6 );
1132 comp->Installed = INSTALLSTATE_ABSENT;
1133 comp->Action = INSTALLSTATE_UNKNOWN;
1134 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1136 comp->Enabled = TRUE;
1138 return comp;
1141 typedef struct {
1142 MSIPACKAGE *package;
1143 MSIFEATURE *feature;
1144 } _ilfs;
1146 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1148 ComponentList *cl;
1150 cl = msi_alloc( sizeof (*cl) );
1151 if ( !cl )
1152 return ERROR_NOT_ENOUGH_MEMORY;
1153 cl->component = comp;
1154 list_add_tail( &feature->Components, &cl->entry );
1156 return ERROR_SUCCESS;
1159 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1161 _ilfs* ilfs= (_ilfs*)param;
1162 MSIPACKAGE *package = ilfs->package;
1163 MSIFEATURE *feature = ilfs->feature;
1164 MSICOMPONENT *comp;
1166 comp = load_component( row );
1167 if (!comp)
1168 return ERROR_FUNCTION_FAILED;
1170 list_add_tail( &package->components, &comp->entry );
1171 add_feature_component( feature, comp );
1173 TRACE("Loaded new component %p\n", comp);
1175 return ERROR_SUCCESS;
1178 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1180 _ilfs* ilfs= (_ilfs*)param;
1181 LPCWSTR component;
1182 DWORD rc;
1183 MSICOMPONENT *comp;
1184 MSIQUERY * view;
1185 static const WCHAR Query[] =
1186 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1187 '`','C','o','m','p','o','n','e','n','t','`',' ',
1188 'W','H','E','R','E',' ',
1189 '`','C','o','m','p','o','n','e','n','t','`',' ',
1190 '=','\'','%','s','\'',0};
1192 component = MSI_RecordGetString(row,1);
1194 /* check to see if the component is already loaded */
1195 comp = get_loaded_component( ilfs->package, component );
1196 if (comp)
1198 TRACE("Component %s already loaded\n", debugstr_w(component) );
1199 add_feature_component( ilfs->feature, comp );
1200 return ERROR_SUCCESS;
1203 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1204 if (rc != ERROR_SUCCESS)
1205 return ERROR_SUCCESS;
1207 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1208 msiobj_release( &view->hdr );
1210 return ERROR_SUCCESS;
1213 static UINT load_feature(MSIRECORD * row, LPVOID param)
1215 MSIPACKAGE* package = (MSIPACKAGE*)param;
1216 MSIFEATURE* feature;
1217 static const WCHAR Query1[] =
1218 {'S','E','L','E','C','T',' ',
1219 '`','C','o','m','p','o','n','e','n','t','_','`',
1220 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1221 'C','o','m','p','o','n','e','n','t','s','`',' ',
1222 'W','H','E','R','E',' ',
1223 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1224 MSIQUERY * view;
1225 UINT rc;
1226 _ilfs ilfs;
1228 /* fill in the data */
1230 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1231 if (!feature)
1232 return ERROR_NOT_ENOUGH_MEMORY;
1234 list_init( &feature->Components );
1236 feature->Feature = msi_dup_record_field( row, 1 );
1238 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1240 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1241 feature->Title = msi_dup_record_field( row, 3 );
1242 feature->Description = msi_dup_record_field( row, 4 );
1244 if (!MSI_RecordIsNull(row,5))
1245 feature->Display = MSI_RecordGetInteger(row,5);
1247 feature->Level= MSI_RecordGetInteger(row,6);
1248 feature->Directory = msi_dup_record_field( row, 7 );
1249 feature->Attributes = MSI_RecordGetInteger(row,8);
1251 feature->Installed = INSTALLSTATE_ABSENT;
1252 feature->Action = INSTALLSTATE_UNKNOWN;
1253 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1255 list_add_tail( &package->features, &feature->entry );
1257 /* load feature components */
1259 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1260 if (rc != ERROR_SUCCESS)
1261 return ERROR_SUCCESS;
1263 ilfs.package = package;
1264 ilfs.feature = feature;
1266 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1267 msiobj_release(&view->hdr);
1269 return ERROR_SUCCESS;
1272 static UINT load_file(MSIRECORD *row, LPVOID param)
1274 MSIPACKAGE* package = (MSIPACKAGE*)param;
1275 LPCWSTR component;
1276 MSIFILE *file;
1278 /* fill in the data */
1280 file = msi_alloc_zero( sizeof (MSIFILE) );
1281 if (!file)
1282 return ERROR_NOT_ENOUGH_MEMORY;
1284 file->File = msi_dup_record_field( row, 1 );
1286 component = MSI_RecordGetString( row, 2 );
1287 file->Component = get_loaded_component( package, component );
1289 if (!file->Component)
1290 ERR("Unfound Component %s\n",debugstr_w(component));
1292 file->FileName = msi_dup_record_field( row, 3 );
1293 reduce_to_longfilename( file->FileName );
1295 file->ShortName = msi_dup_record_field( row, 3 );
1296 reduce_to_shortfilename( file->ShortName );
1298 file->FileSize = MSI_RecordGetInteger( row, 4 );
1299 file->Version = msi_dup_record_field( row, 5 );
1300 file->Language = msi_dup_record_field( row, 6 );
1301 file->Attributes = MSI_RecordGetInteger( row, 7 );
1302 file->Sequence = MSI_RecordGetInteger( row, 8 );
1304 file->state = msifs_invalid;
1306 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1308 list_add_tail( &package->files, &file->entry );
1310 return ERROR_SUCCESS;
1313 static UINT load_all_files(MSIPACKAGE *package)
1315 MSIQUERY * view;
1316 UINT rc;
1317 static const WCHAR Query[] =
1318 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1319 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1320 '`','S','e','q','u','e','n','c','e','`', 0};
1322 if (!package)
1323 return ERROR_INVALID_HANDLE;
1325 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1326 if (rc != ERROR_SUCCESS)
1327 return ERROR_SUCCESS;
1329 rc = MSI_IterateRecords(view, NULL, load_file, package);
1330 msiobj_release(&view->hdr);
1332 return ERROR_SUCCESS;
1337 * I am not doing any of the costing functionality yet.
1338 * Mostly looking at doing the Component and Feature loading
1340 * The native MSI does A LOT of modification to tables here. Mostly adding
1341 * a lot of temporary columns to the Feature and Component tables.
1343 * note: Native msi also tracks the short filename. But I am only going to
1344 * track the long ones. Also looking at this directory table
1345 * it appears that the directory table does not get the parents
1346 * resolved base on property only based on their entries in the
1347 * directory table.
1349 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1351 MSIQUERY * view;
1352 UINT rc;
1353 static const WCHAR Query_all[] =
1354 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1355 '`','F','e','a','t','u','r','e','`',0};
1356 static const WCHAR szCosting[] =
1357 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1358 static const WCHAR szZero[] = { '0', 0 };
1360 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1361 return ERROR_SUCCESS;
1363 MSI_SetPropertyW(package, szCosting, szZero);
1364 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1366 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1367 if (rc != ERROR_SUCCESS)
1368 return rc;
1370 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1371 msiobj_release(&view->hdr);
1373 load_all_files(package);
1375 return ERROR_SUCCESS;
1378 static UINT execute_script(MSIPACKAGE *package, UINT script )
1380 int i;
1381 UINT rc = ERROR_SUCCESS;
1383 TRACE("Executing Script %i\n",script);
1385 if (!package->script)
1387 ERR("no script!\n");
1388 return ERROR_FUNCTION_FAILED;
1391 for (i = 0; i < package->script->ActionCount[script]; i++)
1393 LPWSTR action;
1394 action = package->script->Actions[script][i];
1395 ui_actionstart(package, action);
1396 TRACE("Executing Action (%s)\n",debugstr_w(action));
1397 rc = ACTION_PerformAction(package, action, TRUE);
1398 msi_free(package->script->Actions[script][i]);
1399 if (rc != ERROR_SUCCESS)
1400 break;
1402 msi_free(package->script->Actions[script]);
1404 package->script->ActionCount[script] = 0;
1405 package->script->Actions[script] = NULL;
1406 return rc;
1409 static UINT ACTION_FileCost(MSIPACKAGE *package)
1411 return ERROR_SUCCESS;
1415 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1417 static const WCHAR Query[] =
1418 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1419 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1420 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1421 ' ','=',' ','\'','%','s','\'',
1423 LPWSTR ptargetdir, targetdir, srcdir;
1424 LPCWSTR parent;
1425 LPWSTR shortname = NULL;
1426 MSIRECORD * row = 0;
1427 MSIFOLDER *folder;
1429 TRACE("Looking for dir %s\n",debugstr_w(dir));
1431 folder = get_loaded_folder( package, dir );
1432 if (folder)
1433 return folder;
1435 TRACE("Working to load %s\n",debugstr_w(dir));
1437 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1438 if (!folder)
1439 return NULL;
1441 folder->Directory = strdupW(dir);
1443 row = MSI_QueryGetRecord(package->db, Query, dir);
1444 if (!row)
1445 return NULL;
1447 ptargetdir = targetdir = msi_dup_record_field(row,3);
1449 /* split src and target dir */
1450 if (strchrW(targetdir,':'))
1452 srcdir=strchrW(targetdir,':');
1453 *srcdir=0;
1454 srcdir ++;
1456 else
1457 srcdir=NULL;
1459 /* for now only pick long filename versions */
1460 if (strchrW(targetdir,'|'))
1462 shortname = targetdir;
1463 targetdir = strchrW(targetdir,'|');
1464 *targetdir = 0;
1465 targetdir ++;
1467 /* for the sourcedir pick the short filename */
1468 if (srcdir && strchrW(srcdir,'|'))
1470 LPWSTR p = strchrW(srcdir,'|');
1471 *p = 0;
1474 /* now check for root dirs */
1475 if (targetdir[0] == '.' && targetdir[1] == 0)
1476 targetdir = NULL;
1478 if (targetdir)
1480 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1481 msi_free( folder->TargetDefault);
1482 folder->TargetDefault = strdupW(targetdir);
1485 if (srcdir)
1486 folder->SourceDefault = strdupW(srcdir);
1487 else if (shortname)
1488 folder->SourceDefault = strdupW(shortname);
1489 else if (targetdir)
1490 folder->SourceDefault = strdupW(targetdir);
1491 msi_free(ptargetdir);
1492 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1494 parent = MSI_RecordGetString(row,2);
1495 if (parent)
1497 folder->Parent = load_folder( package, parent );
1498 if ( folder->Parent )
1499 TRACE("loaded parent %p %s\n", folder->Parent,
1500 debugstr_w(folder->Parent->Directory));
1501 else
1502 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1505 folder->Property = msi_dup_property( package, dir );
1507 msiobj_release(&row->hdr);
1509 list_add_tail( &package->folders, &folder->entry );
1511 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1513 return folder;
1516 /* scan for and update current install states */
1517 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1519 MSICOMPONENT *comp;
1520 MSIFEATURE *feature;
1522 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1524 INSTALLSTATE res;
1525 res = MsiGetComponentPathW( package->ProductCode,
1526 comp->ComponentId, NULL, NULL);
1527 if (res < 0)
1528 res = INSTALLSTATE_ABSENT;
1529 comp->Installed = res;
1532 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1534 ComponentList *cl;
1535 INSTALLSTATE res = -10;
1537 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1539 comp= cl->component;
1541 if (res == -10)
1542 res = comp->Installed;
1543 else
1545 if (res == comp->Installed)
1546 continue;
1548 if (res != comp->Installed)
1549 res = INSTALLSTATE_INCOMPLETE;
1552 feature->Installed = res;
1556 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1557 INSTALLSTATE state)
1559 static const WCHAR all[]={'A','L','L',0};
1560 LPWSTR override;
1561 MSIFEATURE *feature;
1563 override = msi_dup_property( package, property );
1564 if (!override)
1565 return FALSE;
1567 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1569 if (strcmpiW(override,all)==0)
1571 feature->ActionRequest= state;
1572 feature->Action = state;
1574 else
1576 LPWSTR ptr = override;
1577 LPWSTR ptr2 = strchrW(override,',');
1579 while (ptr)
1581 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1582 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1584 feature->ActionRequest= state;
1585 feature->Action = state;
1586 break;
1588 if (ptr2)
1590 ptr=ptr2+1;
1591 ptr2 = strchrW(ptr,',');
1593 else
1594 break;
1598 msi_free(override);
1600 return TRUE;
1603 static UINT SetFeatureStates(MSIPACKAGE *package)
1605 int install_level;
1606 static const WCHAR szlevel[] =
1607 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1608 static const WCHAR szAddLocal[] =
1609 {'A','D','D','L','O','C','A','L',0};
1610 static const WCHAR szRemove[] =
1611 {'R','E','M','O','V','E',0};
1612 static const WCHAR szReinstall[] =
1613 {'R','E','I','N','S','T','A','L','L',0};
1614 BOOL override = FALSE;
1615 MSICOMPONENT* component;
1616 MSIFEATURE *feature;
1619 /* I do not know if this is where it should happen.. but */
1621 TRACE("Checking Install Level\n");
1623 install_level = msi_get_property_int( package, szlevel, 1 );
1625 /* ok hereis the _real_ rub
1626 * all these activation/deactivation things happen in order and things
1627 * later on the list override things earlier on the list.
1628 * 1) INSTALLLEVEL processing
1629 * 2) ADDLOCAL
1630 * 3) REMOVE
1631 * 4) ADDSOURCE
1632 * 5) ADDDEFAULT
1633 * 6) REINSTALL
1634 * 7) COMPADDLOCAL
1635 * 8) COMPADDSOURCE
1636 * 9) FILEADDLOCAL
1637 * 10) FILEADDSOURCE
1638 * 11) FILEADDDEFAULT
1639 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1640 * ignored for all the features. seems strange, especially since it is not
1641 * documented anywhere, but it is how it works.
1643 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1644 * REMOVE are the big ones, since we don't handle administrative installs
1645 * yet anyway.
1647 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1648 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1649 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1651 if (!override)
1653 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1655 BOOL feature_state = ((feature->Level > 0) &&
1656 (feature->Level <= install_level));
1658 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1660 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1662 feature->ActionRequest = INSTALLSTATE_SOURCE;
1663 feature->Action = INSTALLSTATE_SOURCE;
1665 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1667 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1668 feature->Action = INSTALLSTATE_ADVERTISED;
1670 else
1672 feature->ActionRequest = INSTALLSTATE_LOCAL;
1673 feature->Action = INSTALLSTATE_LOCAL;
1678 else
1680 /* set the Preselected Property */
1681 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1682 static const WCHAR szOne[] = { '1', 0 };
1684 MSI_SetPropertyW(package,szPreselected,szOne);
1688 * now we want to enable or disable components base on feature
1691 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1693 ComponentList *cl;
1695 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1696 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1697 feature->ActionRequest);
1699 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1701 component = cl->component;
1703 if (!component->Enabled)
1705 component->Action = INSTALLSTATE_UNKNOWN;
1706 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1708 else
1710 if (feature->Action == INSTALLSTATE_LOCAL)
1712 component->Action = INSTALLSTATE_LOCAL;
1713 component->ActionRequest = INSTALLSTATE_LOCAL;
1715 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1717 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1718 (component->Action == INSTALLSTATE_ABSENT) ||
1719 (component->Action == INSTALLSTATE_ADVERTISED))
1722 component->Action = INSTALLSTATE_SOURCE;
1723 component->ActionRequest = INSTALLSTATE_SOURCE;
1726 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1728 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1729 (component->Action == INSTALLSTATE_ABSENT))
1732 component->Action = INSTALLSTATE_ADVERTISED;
1733 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1736 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1738 if (component->Action == INSTALLSTATE_UNKNOWN)
1740 component->Action = INSTALLSTATE_ABSENT;
1741 component->ActionRequest = INSTALLSTATE_ABSENT;
1748 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1750 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1751 debugstr_w(component->Component), component->Installed,
1752 component->Action, component->ActionRequest);
1756 return ERROR_SUCCESS;
1759 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1761 MSIPACKAGE *package = (MSIPACKAGE*)param;
1762 LPCWSTR name;
1763 LPWSTR path;
1765 name = MSI_RecordGetString(row,1);
1767 /* This helper function now does ALL the work */
1768 TRACE("Dir %s ...\n",debugstr_w(name));
1769 load_folder(package,name);
1770 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1771 TRACE("resolves to %s\n",debugstr_w(path));
1772 msi_free(path);
1774 return ERROR_SUCCESS;
1777 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1779 MSIPACKAGE *package = (MSIPACKAGE*)param;
1780 LPCWSTR name;
1781 MSIFEATURE *feature;
1783 name = MSI_RecordGetString( row, 1 );
1785 feature = get_loaded_feature( package, name );
1786 if (!feature)
1787 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1788 else
1790 LPCWSTR Condition;
1791 Condition = MSI_RecordGetString(row,3);
1793 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1795 int level = MSI_RecordGetInteger(row,2);
1796 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1797 feature->Level = level;
1800 return ERROR_SUCCESS;
1805 * A lot is done in this function aside from just the costing.
1806 * The costing needs to be implemented at some point but for now I am going
1807 * to focus on the directory building
1810 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1812 static const WCHAR ExecSeqQuery[] =
1813 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1814 '`','D','i','r','e','c','t','o','r','y','`',0};
1815 static const WCHAR ConditionQuery[] =
1816 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1817 '`','C','o','n','d','i','t','i','o','n','`',0};
1818 static const WCHAR szCosting[] =
1819 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1820 static const WCHAR szlevel[] =
1821 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1822 static const WCHAR szOne[] = { '1', 0 };
1823 MSICOMPONENT *comp;
1824 MSIFILE *file;
1825 UINT rc;
1826 MSIQUERY * view;
1827 LPWSTR level;
1829 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1830 return ERROR_SUCCESS;
1832 TRACE("Building Directory properties\n");
1834 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1835 if (rc == ERROR_SUCCESS)
1837 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1838 package);
1839 msiobj_release(&view->hdr);
1842 TRACE("File calculations\n");
1844 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1846 MSICOMPONENT* comp = file->Component;
1847 LPWSTR p;
1849 if (!comp)
1850 continue;
1852 /* calculate target */
1853 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1855 msi_free(file->TargetPath);
1857 TRACE("file %s is named %s\n",
1858 debugstr_w(file->File),debugstr_w(file->FileName));
1860 file->TargetPath = build_directory_name(2, p, file->FileName);
1862 msi_free(p);
1864 TRACE("file %s resolves to %s\n",
1865 debugstr_w(file->File),debugstr_w(file->TargetPath));
1867 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1869 file->state = msifs_missing;
1870 comp->Cost += file->FileSize;
1871 continue;
1874 if (file->Version)
1876 DWORD handle;
1877 DWORD versize;
1878 UINT sz;
1879 LPVOID version;
1880 static WCHAR name[] = {'\\',0};
1881 static const WCHAR name_fmt[] =
1882 {'%','u','.','%','u','.','%','u','.','%','u',0};
1883 WCHAR filever[0x100];
1884 VS_FIXEDFILEINFO *lpVer;
1886 TRACE("Version comparison..\n");
1887 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1888 version = msi_alloc(versize);
1889 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1891 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1893 sprintfW(filever,name_fmt,
1894 HIWORD(lpVer->dwFileVersionMS),
1895 LOWORD(lpVer->dwFileVersionMS),
1896 HIWORD(lpVer->dwFileVersionLS),
1897 LOWORD(lpVer->dwFileVersionLS));
1899 TRACE("new %s old %s\n", debugstr_w(file->Version),
1900 debugstr_w(filever));
1901 if (strcmpiW(filever,file->Version)<0)
1903 file->state = msifs_overwrite;
1904 /* FIXME: cost should be diff in size */
1905 comp->Cost += file->FileSize;
1907 else
1908 file->state = msifs_present;
1909 msi_free(version);
1911 else
1912 file->state = msifs_present;
1915 TRACE("Evaluating Condition Table\n");
1917 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1918 if (rc == ERROR_SUCCESS)
1920 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1921 package);
1922 msiobj_release(&view->hdr);
1925 TRACE("Enabling or Disabling Components\n");
1926 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1928 if (comp->Condition)
1930 if (MSI_EvaluateConditionW(package,
1931 comp->Condition) == MSICONDITION_FALSE)
1933 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1934 comp->Enabled = FALSE;
1939 MSI_SetPropertyW(package,szCosting,szOne);
1940 /* set default run level if not set */
1941 level = msi_dup_property( package, szlevel );
1942 if (!level)
1943 MSI_SetPropertyW(package,szlevel, szOne);
1944 msi_free(level);
1946 ACTION_UpdateInstallStates(package);
1948 return SetFeatureStates(package);
1951 /* OK this value is "interpreted" and then formatted based on the
1952 first few characters */
1953 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1954 DWORD *size)
1956 LPSTR data = NULL;
1957 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1959 if (value[1]=='x')
1961 LPWSTR ptr;
1962 CHAR byte[5];
1963 LPWSTR deformated = NULL;
1964 int count;
1966 deformat_string(package, &value[2], &deformated);
1968 /* binary value type */
1969 ptr = deformated;
1970 *type = REG_BINARY;
1971 if (strlenW(ptr)%2)
1972 *size = (strlenW(ptr)/2)+1;
1973 else
1974 *size = strlenW(ptr)/2;
1976 data = msi_alloc(*size);
1978 byte[0] = '0';
1979 byte[1] = 'x';
1980 byte[4] = 0;
1981 count = 0;
1982 /* if uneven pad with a zero in front */
1983 if (strlenW(ptr)%2)
1985 byte[2]= '0';
1986 byte[3]= *ptr;
1987 ptr++;
1988 data[count] = (BYTE)strtol(byte,NULL,0);
1989 count ++;
1990 TRACE("Uneven byte count\n");
1992 while (*ptr)
1994 byte[2]= *ptr;
1995 ptr++;
1996 byte[3]= *ptr;
1997 ptr++;
1998 data[count] = (BYTE)strtol(byte,NULL,0);
1999 count ++;
2001 msi_free(deformated);
2003 TRACE("Data %li bytes(%i)\n",*size,count);
2005 else
2007 LPWSTR deformated;
2008 LPWSTR p;
2009 DWORD d = 0;
2010 deformat_string(package, &value[1], &deformated);
2012 *type=REG_DWORD;
2013 *size = sizeof(DWORD);
2014 data = msi_alloc(*size);
2015 p = deformated;
2016 if (*p == '-')
2017 p++;
2018 while (*p)
2020 if ( (*p < '0') || (*p > '9') )
2021 break;
2022 d *= 10;
2023 d += (*p - '0');
2024 p++;
2026 if (deformated[0] == '-')
2027 d = -d;
2028 *(LPDWORD)data = d;
2029 TRACE("DWORD %li\n",*(LPDWORD)data);
2031 msi_free(deformated);
2034 else
2036 static const WCHAR szMulti[] = {'[','~',']',0};
2037 LPCWSTR ptr;
2038 *type=REG_SZ;
2040 if (value[0]=='#')
2042 if (value[1]=='%')
2044 ptr = &value[2];
2045 *type=REG_EXPAND_SZ;
2047 else
2048 ptr = &value[1];
2050 else
2051 ptr=value;
2053 if (strstrW(value,szMulti))
2054 *type = REG_MULTI_SZ;
2056 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2058 return data;
2061 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2063 MSIPACKAGE *package = (MSIPACKAGE*)param;
2064 static const WCHAR szHCR[] =
2065 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2066 'R','O','O','T','\\',0};
2067 static const WCHAR szHCU[] =
2068 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2069 'U','S','E','R','\\',0};
2070 static const WCHAR szHLM[] =
2071 {'H','K','E','Y','_','L','O','C','A','L','_',
2072 'M','A','C','H','I','N','E','\\',0};
2073 static const WCHAR szHU[] =
2074 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2076 LPSTR value_data = NULL;
2077 HKEY root_key, hkey;
2078 DWORD type,size;
2079 LPWSTR deformated;
2080 LPCWSTR szRoot, component, name, key, value;
2081 MSICOMPONENT *comp;
2082 MSIRECORD * uirow;
2083 LPWSTR uikey;
2084 INT root;
2085 BOOL check_first = FALSE;
2086 UINT rc;
2088 ui_progress(package,2,0,0,0);
2090 value = NULL;
2091 key = NULL;
2092 uikey = NULL;
2093 name = NULL;
2095 component = MSI_RecordGetString(row, 6);
2096 comp = get_loaded_component(package,component);
2097 if (!comp)
2098 return ERROR_SUCCESS;
2100 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2102 TRACE("Skipping write due to disabled component %s\n",
2103 debugstr_w(component));
2105 comp->Action = comp->Installed;
2107 return ERROR_SUCCESS;
2110 comp->Action = INSTALLSTATE_LOCAL;
2112 name = MSI_RecordGetString(row, 4);
2113 if( MSI_RecordIsNull(row,5) && name )
2115 /* null values can have special meanings */
2116 if (name[0]=='-' && name[1] == 0)
2117 return ERROR_SUCCESS;
2118 else if ((name[0]=='+' && name[1] == 0) ||
2119 (name[0] == '*' && name[1] == 0))
2120 name = NULL;
2121 check_first = TRUE;
2124 root = MSI_RecordGetInteger(row,2);
2125 key = MSI_RecordGetString(row, 3);
2127 /* get the root key */
2128 switch (root)
2130 case -1:
2132 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2133 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2134 if (all_users && all_users[0] == '1')
2136 root_key = HKEY_LOCAL_MACHINE;
2137 szRoot = szHLM;
2139 else
2141 root_key = HKEY_CURRENT_USER;
2142 szRoot = szHCU;
2144 msi_free(all_users);
2146 break;
2147 case 0: root_key = HKEY_CLASSES_ROOT;
2148 szRoot = szHCR;
2149 break;
2150 case 1: root_key = HKEY_CURRENT_USER;
2151 szRoot = szHCU;
2152 break;
2153 case 2: root_key = HKEY_LOCAL_MACHINE;
2154 szRoot = szHLM;
2155 break;
2156 case 3: root_key = HKEY_USERS;
2157 szRoot = szHU;
2158 break;
2159 default:
2160 ERR("Unknown root %i\n",root);
2161 root_key=NULL;
2162 szRoot = NULL;
2163 break;
2165 if (!root_key)
2166 return ERROR_SUCCESS;
2168 deformat_string(package, key , &deformated);
2169 size = strlenW(deformated) + strlenW(szRoot) + 1;
2170 uikey = msi_alloc(size*sizeof(WCHAR));
2171 strcpyW(uikey,szRoot);
2172 strcatW(uikey,deformated);
2174 if (RegCreateKeyW( root_key, deformated, &hkey))
2176 ERR("Could not create key %s\n",debugstr_w(deformated));
2177 msi_free(deformated);
2178 msi_free(uikey);
2179 return ERROR_SUCCESS;
2181 msi_free(deformated);
2183 value = MSI_RecordGetString(row,5);
2184 if (value)
2185 value_data = parse_value(package, value, &type, &size);
2186 else
2188 static const WCHAR szEmpty[] = {0};
2189 value_data = (LPSTR)strdupW(szEmpty);
2190 size = 0;
2191 type = REG_SZ;
2194 deformat_string(package, name, &deformated);
2196 /* get the double nulls to terminate SZ_MULTI */
2197 if (type == REG_MULTI_SZ)
2198 size +=sizeof(WCHAR);
2200 if (!check_first)
2202 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2203 debugstr_w(uikey));
2204 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2206 else
2208 DWORD sz = 0;
2209 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2210 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2212 TRACE("value %s of %s checked already exists\n",
2213 debugstr_w(deformated), debugstr_w(uikey));
2215 else
2217 TRACE("Checked and setting value %s of %s\n",
2218 debugstr_w(deformated), debugstr_w(uikey));
2219 if (deformated || size)
2220 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2223 RegCloseKey(hkey);
2225 uirow = MSI_CreateRecord(3);
2226 MSI_RecordSetStringW(uirow,2,deformated);
2227 MSI_RecordSetStringW(uirow,1,uikey);
2229 if (type == REG_SZ)
2230 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2231 else
2232 MSI_RecordSetStringW(uirow,3,value);
2234 ui_actiondata(package,szWriteRegistryValues,uirow);
2235 msiobj_release( &uirow->hdr );
2237 msi_free(value_data);
2238 msi_free(deformated);
2239 msi_free(uikey);
2241 return ERROR_SUCCESS;
2244 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2246 UINT rc;
2247 MSIQUERY * view;
2248 static const WCHAR ExecSeqQuery[] =
2249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2250 '`','R','e','g','i','s','t','r','y','`',0 };
2252 if (!package)
2253 return ERROR_INVALID_HANDLE;
2255 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2256 if (rc != ERROR_SUCCESS)
2257 return ERROR_SUCCESS;
2259 /* increment progress bar each time action data is sent */
2260 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2262 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2264 msiobj_release(&view->hdr);
2265 return rc;
2268 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2270 package->script->CurrentlyScripting = TRUE;
2272 return ERROR_SUCCESS;
2276 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2278 MSICOMPONENT *comp;
2279 DWORD progress = 0;
2280 DWORD total = 0;
2281 static const WCHAR q1[]=
2282 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2283 '`','R','e','g','i','s','t','r','y','`',0};
2284 UINT rc;
2285 MSIQUERY * view;
2286 MSIFEATURE *feature;
2287 MSIFILE *file;
2289 TRACE("InstallValidate\n");
2291 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2292 if (rc == ERROR_SUCCESS)
2294 MSI_IterateRecords( view, &progress, NULL, package );
2295 msiobj_release( &view->hdr );
2296 total += progress * REG_PROGRESS_VALUE;
2299 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2300 total += COMPONENT_PROGRESS_VALUE;
2302 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2303 total += file->FileSize;
2305 ui_progress(package,0,total,0,0);
2307 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2309 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2310 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2311 feature->ActionRequest);
2314 return ERROR_SUCCESS;
2317 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2319 MSIPACKAGE* package = (MSIPACKAGE*)param;
2320 LPCWSTR cond = NULL;
2321 LPCWSTR message = NULL;
2322 static const WCHAR title[]=
2323 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2325 cond = MSI_RecordGetString(row,1);
2327 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2329 LPWSTR deformated;
2330 message = MSI_RecordGetString(row,2);
2331 deformat_string(package,message,&deformated);
2332 MessageBoxW(NULL,deformated,title,MB_OK);
2333 msi_free(deformated);
2334 return ERROR_FUNCTION_FAILED;
2337 return ERROR_SUCCESS;
2340 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2342 UINT rc;
2343 MSIQUERY * view = NULL;
2344 static const WCHAR ExecSeqQuery[] =
2345 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2346 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2348 TRACE("Checking launch conditions\n");
2350 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2351 if (rc != ERROR_SUCCESS)
2352 return ERROR_SUCCESS;
2354 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2355 msiobj_release(&view->hdr);
2357 return rc;
2360 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2363 if (!cmp->KeyPath)
2364 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2366 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2368 MSIRECORD * row = 0;
2369 UINT root,len;
2370 LPWSTR deformated,buffer,deformated_name;
2371 LPCWSTR key,name;
2372 static const WCHAR ExecSeqQuery[] =
2373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2374 '`','R','e','g','i','s','t','r','y','`',' ',
2375 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2376 ' ','=',' ' ,'\'','%','s','\'',0 };
2377 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2378 static const WCHAR fmt2[]=
2379 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2381 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2382 if (!row)
2383 return NULL;
2385 root = MSI_RecordGetInteger(row,2);
2386 key = MSI_RecordGetString(row, 3);
2387 name = MSI_RecordGetString(row, 4);
2388 deformat_string(package, key , &deformated);
2389 deformat_string(package, name, &deformated_name);
2391 len = strlenW(deformated) + 6;
2392 if (deformated_name)
2393 len+=strlenW(deformated_name);
2395 buffer = msi_alloc( len *sizeof(WCHAR));
2397 if (deformated_name)
2398 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2399 else
2400 sprintfW(buffer,fmt,root,deformated);
2402 msi_free(deformated);
2403 msi_free(deformated_name);
2404 msiobj_release(&row->hdr);
2406 return buffer;
2408 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2410 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2411 return NULL;
2413 else
2415 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2417 if (file)
2418 return strdupW( file->TargetPath );
2420 return NULL;
2423 static HKEY openSharedDLLsKey(void)
2425 HKEY hkey=0;
2426 static const WCHAR path[] =
2427 {'S','o','f','t','w','a','r','e','\\',
2428 'M','i','c','r','o','s','o','f','t','\\',
2429 'W','i','n','d','o','w','s','\\',
2430 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2431 'S','h','a','r','e','d','D','L','L','s',0};
2433 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2434 return hkey;
2437 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2439 HKEY hkey;
2440 DWORD count=0;
2441 DWORD type;
2442 DWORD sz = sizeof(count);
2443 DWORD rc;
2445 hkey = openSharedDLLsKey();
2446 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2447 if (rc != ERROR_SUCCESS)
2448 count = 0;
2449 RegCloseKey(hkey);
2450 return count;
2453 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2455 HKEY hkey;
2457 hkey = openSharedDLLsKey();
2458 if (count > 0)
2459 msi_reg_set_val_dword( hkey, path, count );
2460 else
2461 RegDeleteValueW(hkey,path);
2462 RegCloseKey(hkey);
2463 return count;
2467 * Return TRUE if the count should be written out and FALSE if not
2469 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2471 MSIFEATURE *feature;
2472 INT count = 0;
2473 BOOL write = FALSE;
2475 /* only refcount DLLs */
2476 if (comp->KeyPath == NULL ||
2477 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2478 comp->Attributes & msidbComponentAttributesODBCDataSource)
2479 write = FALSE;
2480 else
2482 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2483 write = (count > 0);
2485 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2486 write = TRUE;
2489 /* increment counts */
2490 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2492 ComponentList *cl;
2494 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2495 continue;
2497 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2499 if ( cl->component == comp )
2500 count++;
2504 /* decrement counts */
2505 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2507 ComponentList *cl;
2509 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2510 continue;
2512 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2514 if ( cl->component == comp )
2515 count--;
2519 /* ref count all the files in the component */
2520 if (write)
2522 MSIFILE *file;
2524 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2526 if (file->Component == comp)
2527 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2531 /* add a count for permenent */
2532 if (comp->Attributes & msidbComponentAttributesPermanent)
2533 count ++;
2535 comp->RefCount = count;
2537 if (write)
2538 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2542 * Ok further analysis makes me think that this work is
2543 * actually done in the PublishComponents and PublishFeatures
2544 * step, and not here. It appears like the keypath and all that is
2545 * resolved in this step, however actually written in the Publish steps.
2546 * But we will leave it here for now because it is unclear
2548 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2550 WCHAR squished_pc[GUID_SIZE];
2551 WCHAR squished_cc[GUID_SIZE];
2552 UINT rc;
2553 MSICOMPONENT *comp;
2554 HKEY hkey=0,hkey2=0;
2556 /* writes the Component and Features values to the registry */
2558 rc = MSIREG_OpenComponents(&hkey);
2559 if (rc != ERROR_SUCCESS)
2560 return rc;
2562 squash_guid(package->ProductCode,squished_pc);
2563 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2565 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2567 MSIRECORD * uirow;
2569 ui_progress(package,2,0,0,0);
2570 if (!comp->ComponentId)
2571 continue;
2573 squash_guid(comp->ComponentId,squished_cc);
2575 msi_free(comp->FullKeypath);
2576 comp->FullKeypath = resolve_keypath( package, comp );
2578 /* do the refcounting */
2579 ACTION_RefCountComponent( package, comp );
2581 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2582 debugstr_w(comp->Component),
2583 debugstr_w(squished_cc),
2584 debugstr_w(comp->FullKeypath),
2585 comp->RefCount);
2587 * Write the keypath out if the component is to be registered
2588 * and delete the key if the component is to be deregistered
2590 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2592 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2593 if (rc != ERROR_SUCCESS)
2594 continue;
2596 if (!comp->FullKeypath)
2597 continue;
2599 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2601 if (comp->Attributes & msidbComponentAttributesPermanent)
2603 static const WCHAR szPermKey[] =
2604 { '0','0','0','0','0','0','0','0','0','0','0','0',
2605 '0','0','0','0','0','0','0','0','0','0','0','0',
2606 '0','0','0','0','0','0','0','0',0 };
2608 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2611 RegCloseKey(hkey2);
2613 /* UI stuff */
2614 uirow = MSI_CreateRecord(3);
2615 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2616 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2617 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2618 ui_actiondata(package,szProcessComponents,uirow);
2619 msiobj_release( &uirow->hdr );
2621 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2623 DWORD res;
2625 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2626 if (rc != ERROR_SUCCESS)
2627 continue;
2629 RegDeleteValueW(hkey2,squished_pc);
2631 /* if the key is empty delete it */
2632 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2633 RegCloseKey(hkey2);
2634 if (res == ERROR_NO_MORE_ITEMS)
2635 RegDeleteKeyW(hkey,squished_cc);
2637 /* UI stuff */
2638 uirow = MSI_CreateRecord(2);
2639 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2640 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2641 ui_actiondata(package,szProcessComponents,uirow);
2642 msiobj_release( &uirow->hdr );
2645 RegCloseKey(hkey);
2646 return rc;
2649 typedef struct {
2650 CLSID clsid;
2651 LPWSTR source;
2653 LPWSTR path;
2654 ITypeLib *ptLib;
2655 } typelib_struct;
2657 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2658 LPWSTR lpszName, LONG_PTR lParam)
2660 TLIBATTR *attr;
2661 typelib_struct *tl_struct = (typelib_struct*) lParam;
2662 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2663 int sz;
2664 HRESULT res;
2666 if (!IS_INTRESOURCE(lpszName))
2668 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2669 return TRUE;
2672 sz = strlenW(tl_struct->source)+4;
2673 sz *= sizeof(WCHAR);
2675 if ((INT)lpszName == 1)
2676 tl_struct->path = strdupW(tl_struct->source);
2677 else
2679 tl_struct->path = msi_alloc(sz);
2680 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2683 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2684 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2685 if (!SUCCEEDED(res))
2687 msi_free(tl_struct->path);
2688 tl_struct->path = NULL;
2690 return TRUE;
2693 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2694 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2696 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2697 return FALSE;
2700 msi_free(tl_struct->path);
2701 tl_struct->path = NULL;
2703 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2704 ITypeLib_Release(tl_struct->ptLib);
2706 return TRUE;
2709 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2711 MSIPACKAGE* package = (MSIPACKAGE*)param;
2712 LPCWSTR component;
2713 MSICOMPONENT *comp;
2714 MSIFILE *file;
2715 typelib_struct tl_struct;
2716 HMODULE module;
2717 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2719 component = MSI_RecordGetString(row,3);
2720 comp = get_loaded_component(package,component);
2721 if (!comp)
2722 return ERROR_SUCCESS;
2724 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2726 TRACE("Skipping typelib reg due to disabled component\n");
2728 comp->Action = comp->Installed;
2730 return ERROR_SUCCESS;
2733 comp->Action = INSTALLSTATE_LOCAL;
2735 file = get_loaded_file( package, comp->KeyPath );
2736 if (!file)
2737 return ERROR_SUCCESS;
2739 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2740 if (module)
2742 LPCWSTR guid;
2743 guid = MSI_RecordGetString(row,1);
2744 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2745 tl_struct.source = strdupW( file->TargetPath );
2746 tl_struct.path = NULL;
2748 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2749 (LONG_PTR)&tl_struct);
2751 if (tl_struct.path)
2753 LPWSTR help = NULL;
2754 LPCWSTR helpid;
2755 HRESULT res;
2757 helpid = MSI_RecordGetString(row,6);
2759 if (helpid)
2760 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2761 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2762 msi_free(help);
2764 if (!SUCCEEDED(res))
2765 ERR("Failed to register type library %s\n",
2766 debugstr_w(tl_struct.path));
2767 else
2769 ui_actiondata(package,szRegisterTypeLibraries,row);
2771 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2774 ITypeLib_Release(tl_struct.ptLib);
2775 msi_free(tl_struct.path);
2777 else
2778 ERR("Failed to load type library %s\n",
2779 debugstr_w(tl_struct.source));
2781 FreeLibrary(module);
2782 msi_free(tl_struct.source);
2784 else
2785 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2787 return ERROR_SUCCESS;
2790 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2793 * OK this is a bit confusing.. I am given a _Component key and I believe
2794 * that the file that is being registered as a type library is the "key file
2795 * of that component" which I interpret to mean "The file in the KeyPath of
2796 * that component".
2798 UINT rc;
2799 MSIQUERY * view;
2800 static const WCHAR Query[] =
2801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2802 '`','T','y','p','e','L','i','b','`',0};
2804 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2805 if (rc != ERROR_SUCCESS)
2806 return ERROR_SUCCESS;
2808 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2809 msiobj_release(&view->hdr);
2810 return rc;
2813 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2815 MSIPACKAGE *package = (MSIPACKAGE*)param;
2816 LPWSTR target_file, target_folder, filename;
2817 LPCWSTR buffer, extension;
2818 MSICOMPONENT *comp;
2819 static const WCHAR szlnk[]={'.','l','n','k',0};
2820 IShellLinkW *sl;
2821 IPersistFile *pf;
2822 HRESULT res;
2824 buffer = MSI_RecordGetString(row,4);
2825 comp = get_loaded_component(package,buffer);
2826 if (!comp)
2827 return ERROR_SUCCESS;
2829 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2831 TRACE("Skipping shortcut creation due to disabled component\n");
2833 comp->Action = comp->Installed;
2835 return ERROR_SUCCESS;
2838 comp->Action = INSTALLSTATE_LOCAL;
2840 ui_actiondata(package,szCreateShortcuts,row);
2842 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2843 &IID_IShellLinkW, (LPVOID *) &sl );
2845 if (FAILED(res))
2847 ERR("Is IID_IShellLink\n");
2848 return ERROR_SUCCESS;
2851 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2852 if( FAILED( res ) )
2854 ERR("Is IID_IPersistFile\n");
2855 return ERROR_SUCCESS;
2858 buffer = MSI_RecordGetString(row,2);
2859 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2861 /* may be needed because of a bug somehwere else */
2862 create_full_pathW(target_folder);
2864 filename = msi_dup_record_field( row, 3 );
2865 reduce_to_longfilename(filename);
2867 extension = strchrW(filename,'.');
2868 if (!extension || strcmpiW(extension,szlnk))
2870 int len = strlenW(filename);
2871 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2872 memcpy(filename + len, szlnk, sizeof(szlnk));
2874 target_file = build_directory_name(2, target_folder, filename);
2875 msi_free(target_folder);
2876 msi_free(filename);
2878 buffer = MSI_RecordGetString(row,5);
2879 if (strchrW(buffer,'['))
2881 LPWSTR deformated;
2882 deformat_string(package,buffer,&deformated);
2883 IShellLinkW_SetPath(sl,deformated);
2884 msi_free(deformated);
2886 else
2888 FIXME("poorly handled shortcut format, advertised shortcut\n");
2889 IShellLinkW_SetPath(sl,comp->FullKeypath);
2892 if (!MSI_RecordIsNull(row,6))
2894 LPWSTR deformated;
2895 buffer = MSI_RecordGetString(row,6);
2896 deformat_string(package,buffer,&deformated);
2897 IShellLinkW_SetArguments(sl,deformated);
2898 msi_free(deformated);
2901 if (!MSI_RecordIsNull(row,7))
2903 buffer = MSI_RecordGetString(row,7);
2904 IShellLinkW_SetDescription(sl,buffer);
2907 if (!MSI_RecordIsNull(row,8))
2908 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2910 if (!MSI_RecordIsNull(row,9))
2912 LPWSTR Path;
2913 INT index;
2915 buffer = MSI_RecordGetString(row,9);
2917 Path = build_icon_path(package,buffer);
2918 index = MSI_RecordGetInteger(row,10);
2920 IShellLinkW_SetIconLocation(sl,Path,index);
2921 msi_free(Path);
2924 if (!MSI_RecordIsNull(row,11))
2925 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2927 if (!MSI_RecordIsNull(row,12))
2929 LPWSTR Path;
2930 buffer = MSI_RecordGetString(row,12);
2931 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2932 IShellLinkW_SetWorkingDirectory(sl,Path);
2933 msi_free(Path);
2936 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2937 IPersistFile_Save(pf,target_file,FALSE);
2939 msi_free(target_file);
2941 IPersistFile_Release( pf );
2942 IShellLinkW_Release( sl );
2944 return ERROR_SUCCESS;
2947 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2949 UINT rc;
2950 HRESULT res;
2951 MSIQUERY * view;
2952 static const WCHAR Query[] =
2953 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2954 '`','S','h','o','r','t','c','u','t','`',0};
2956 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2957 if (rc != ERROR_SUCCESS)
2958 return ERROR_SUCCESS;
2960 res = CoInitialize( NULL );
2961 if (FAILED (res))
2963 ERR("CoInitialize failed\n");
2964 return ERROR_FUNCTION_FAILED;
2967 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2968 msiobj_release(&view->hdr);
2970 CoUninitialize();
2972 return rc;
2975 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2977 MSIPACKAGE* package = (MSIPACKAGE*)param;
2978 HANDLE the_file;
2979 LPWSTR FilePath;
2980 LPCWSTR FileName;
2981 CHAR buffer[1024];
2982 DWORD sz;
2983 UINT rc;
2984 MSIRECORD *uirow;
2986 FileName = MSI_RecordGetString(row,1);
2987 if (!FileName)
2989 ERR("Unable to get FileName\n");
2990 return ERROR_SUCCESS;
2993 FilePath = build_icon_path(package,FileName);
2995 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2997 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2998 FILE_ATTRIBUTE_NORMAL, NULL);
3000 if (the_file == INVALID_HANDLE_VALUE)
3002 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3003 msi_free(FilePath);
3004 return ERROR_SUCCESS;
3009 DWORD write;
3010 sz = 1024;
3011 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3012 if (rc != ERROR_SUCCESS)
3014 ERR("Failed to get stream\n");
3015 CloseHandle(the_file);
3016 DeleteFileW(FilePath);
3017 break;
3019 WriteFile(the_file,buffer,sz,&write,NULL);
3020 } while (sz == 1024);
3022 msi_free(FilePath);
3024 CloseHandle(the_file);
3026 uirow = MSI_CreateRecord(1);
3027 MSI_RecordSetStringW(uirow,1,FileName);
3028 ui_actiondata(package,szPublishProduct,uirow);
3029 msiobj_release( &uirow->hdr );
3031 return ERROR_SUCCESS;
3035 * 99% of the work done here is only done for
3036 * advertised installs. However this is where the
3037 * Icon table is processed and written out
3038 * so that is what I am going to do here.
3040 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3042 UINT rc;
3043 MSIQUERY * view;
3044 static const WCHAR Query[]=
3045 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3046 '`','I','c','o','n','`',0};
3047 /* for registry stuff */
3048 HKEY hkey=0;
3049 HKEY hukey=0;
3050 static const WCHAR szProductLanguage[] =
3051 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3052 static const WCHAR szARPProductIcon[] =
3053 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3054 static const WCHAR szProductVersion[] =
3055 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3056 DWORD langid;
3057 LPWSTR buffer;
3058 DWORD size;
3059 MSIHANDLE hDb, hSumInfo;
3061 /* write out icon files */
3063 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3064 if (rc == ERROR_SUCCESS)
3066 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3067 msiobj_release(&view->hdr);
3070 /* ok there is a lot more done here but i need to figure out what */
3072 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3073 if (rc != ERROR_SUCCESS)
3074 goto end;
3076 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3077 if (rc != ERROR_SUCCESS)
3078 goto end;
3081 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3082 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3083 msi_free(buffer);
3085 langid = msi_get_property_int( package, szProductLanguage, 0 );
3086 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3088 buffer = msi_dup_property( package, szARPProductIcon );
3089 if (buffer)
3091 LPWSTR path = build_icon_path(package,buffer);
3092 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3093 msi_free( path );
3095 msi_free(buffer);
3097 buffer = msi_dup_property( package, szProductVersion );
3098 if (buffer)
3100 DWORD verdword = build_version_dword(buffer);
3101 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3103 msi_free(buffer);
3105 /* FIXME: Need to write more keys to the user registry */
3107 hDb= alloc_msihandle( &package->db->hdr );
3108 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3109 MsiCloseHandle(hDb);
3110 if (rc == ERROR_SUCCESS)
3112 WCHAR guidbuffer[0x200];
3113 size = 0x200;
3114 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3115 guidbuffer, &size);
3116 if (rc == ERROR_SUCCESS)
3118 WCHAR squashed[GUID_SIZE];
3119 /* for now we only care about the first guid */
3120 LPWSTR ptr = strchrW(guidbuffer,';');
3121 if (ptr) *ptr = 0;
3122 squash_guid(guidbuffer,squashed);
3123 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3125 else
3127 ERR("Unable to query Revision_Number...\n");
3128 rc = ERROR_SUCCESS;
3130 MsiCloseHandle(hSumInfo);
3132 else
3134 ERR("Unable to open Summary Information\n");
3135 rc = ERROR_SUCCESS;
3138 end:
3140 RegCloseKey(hkey);
3141 RegCloseKey(hukey);
3143 return rc;
3146 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3148 MSIPACKAGE *package = (MSIPACKAGE*)param;
3149 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3150 LPWSTR deformated_section, deformated_key, deformated_value;
3151 LPWSTR folder, fullname = NULL;
3152 MSIRECORD * uirow;
3153 INT action;
3154 MSICOMPONENT *comp;
3155 static const WCHAR szWindowsFolder[] =
3156 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3158 component = MSI_RecordGetString(row, 8);
3159 comp = get_loaded_component(package,component);
3161 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3163 TRACE("Skipping ini file due to disabled component %s\n",
3164 debugstr_w(component));
3166 comp->Action = comp->Installed;
3168 return ERROR_SUCCESS;
3171 comp->Action = INSTALLSTATE_LOCAL;
3173 identifier = MSI_RecordGetString(row,1);
3174 filename = MSI_RecordGetString(row,2);
3175 dirproperty = MSI_RecordGetString(row,3);
3176 section = MSI_RecordGetString(row,4);
3177 key = MSI_RecordGetString(row,5);
3178 value = MSI_RecordGetString(row,6);
3179 action = MSI_RecordGetInteger(row,7);
3181 deformat_string(package,section,&deformated_section);
3182 deformat_string(package,key,&deformated_key);
3183 deformat_string(package,value,&deformated_value);
3185 if (dirproperty)
3187 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3188 if (!folder)
3189 folder = msi_dup_property( package, dirproperty );
3191 else
3192 folder = msi_dup_property( package, szWindowsFolder );
3194 if (!folder)
3196 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3197 goto cleanup;
3200 fullname = build_directory_name(2, folder, filename);
3202 if (action == 0)
3204 TRACE("Adding value %s to section %s in %s\n",
3205 debugstr_w(deformated_key), debugstr_w(deformated_section),
3206 debugstr_w(fullname));
3207 WritePrivateProfileStringW(deformated_section, deformated_key,
3208 deformated_value, fullname);
3210 else if (action == 1)
3212 WCHAR returned[10];
3213 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3214 returned, 10, fullname);
3215 if (returned[0] == 0)
3217 TRACE("Adding value %s to section %s in %s\n",
3218 debugstr_w(deformated_key), debugstr_w(deformated_section),
3219 debugstr_w(fullname));
3221 WritePrivateProfileStringW(deformated_section, deformated_key,
3222 deformated_value, fullname);
3225 else if (action == 3)
3226 FIXME("Append to existing section not yet implemented\n");
3228 uirow = MSI_CreateRecord(4);
3229 MSI_RecordSetStringW(uirow,1,identifier);
3230 MSI_RecordSetStringW(uirow,2,deformated_section);
3231 MSI_RecordSetStringW(uirow,3,deformated_key);
3232 MSI_RecordSetStringW(uirow,4,deformated_value);
3233 ui_actiondata(package,szWriteIniValues,uirow);
3234 msiobj_release( &uirow->hdr );
3235 cleanup:
3236 msi_free(fullname);
3237 msi_free(folder);
3238 msi_free(deformated_key);
3239 msi_free(deformated_value);
3240 msi_free(deformated_section);
3241 return ERROR_SUCCESS;
3244 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3246 UINT rc;
3247 MSIQUERY * view;
3248 static const WCHAR ExecSeqQuery[] =
3249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3250 '`','I','n','i','F','i','l','e','`',0};
3252 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3253 if (rc != ERROR_SUCCESS)
3255 TRACE("no IniFile table\n");
3256 return ERROR_SUCCESS;
3259 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3260 msiobj_release(&view->hdr);
3261 return rc;
3264 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3266 MSIPACKAGE *package = (MSIPACKAGE*)param;
3267 LPCWSTR filename;
3268 LPWSTR FullName;
3269 MSIFILE *file;
3270 DWORD len;
3271 static const WCHAR ExeStr[] =
3272 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3273 static const WCHAR close[] = {'\"',0};
3274 STARTUPINFOW si;
3275 PROCESS_INFORMATION info;
3276 BOOL brc;
3277 MSIRECORD *uirow;
3278 LPWSTR uipath, p;
3280 memset(&si,0,sizeof(STARTUPINFOW));
3282 filename = MSI_RecordGetString(row,1);
3283 file = get_loaded_file( package, filename );
3285 if (!file)
3287 ERR("Unable to find file id %s\n",debugstr_w(filename));
3288 return ERROR_SUCCESS;
3291 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3293 FullName = msi_alloc(len*sizeof(WCHAR));
3294 strcpyW(FullName,ExeStr);
3295 strcatW( FullName, file->TargetPath );
3296 strcatW(FullName,close);
3298 TRACE("Registering %s\n",debugstr_w(FullName));
3299 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3300 &si, &info);
3302 if (brc)
3303 msi_dialog_check_messages(info.hProcess);
3305 msi_free(FullName);
3307 /* the UI chunk */
3308 uirow = MSI_CreateRecord( 2 );
3309 uipath = strdupW( file->TargetPath );
3310 p = strrchrW(uipath,'\\');
3311 if (p)
3312 p[1]=0;
3313 MSI_RecordSetStringW( uirow, 1, &p[2] );
3314 MSI_RecordSetStringW( uirow, 2, uipath);
3315 ui_actiondata( package, szSelfRegModules, uirow);
3316 msiobj_release( &uirow->hdr );
3317 msi_free( uipath );
3318 /* FIXME: call ui_progress? */
3320 return ERROR_SUCCESS;
3323 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3325 UINT rc;
3326 MSIQUERY * view;
3327 static const WCHAR ExecSeqQuery[] =
3328 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3329 '`','S','e','l','f','R','e','g','`',0};
3331 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3332 if (rc != ERROR_SUCCESS)
3334 TRACE("no SelfReg table\n");
3335 return ERROR_SUCCESS;
3338 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3339 msiobj_release(&view->hdr);
3341 return ERROR_SUCCESS;
3344 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3346 MSIFEATURE *feature;
3347 UINT rc;
3348 HKEY hkey=0;
3349 HKEY hukey=0;
3351 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3352 if (rc != ERROR_SUCCESS)
3353 goto end;
3355 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3356 if (rc != ERROR_SUCCESS)
3357 goto end;
3359 /* here the guids are base 85 encoded */
3360 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3362 ComponentList *cl;
3363 LPWSTR data = NULL;
3364 GUID clsid;
3365 INT size;
3366 BOOL absent = FALSE;
3367 MSIRECORD *uirow;
3369 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3370 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3371 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3372 absent = TRUE;
3374 size = 1;
3375 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3377 size += 21;
3379 if (feature->Feature_Parent)
3380 size += strlenW( feature->Feature_Parent )+2;
3382 data = msi_alloc(size * sizeof(WCHAR));
3384 data[0] = 0;
3385 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3387 MSICOMPONENT* component = cl->component;
3388 WCHAR buf[21];
3390 memset(buf,0,sizeof(buf));
3391 if (component->ComponentId)
3393 TRACE("From %s\n",debugstr_w(component->ComponentId));
3394 CLSIDFromString(component->ComponentId, &clsid);
3395 encode_base85_guid(&clsid,buf);
3396 TRACE("to %s\n",debugstr_w(buf));
3397 strcatW(data,buf);
3400 if (feature->Feature_Parent)
3402 static const WCHAR sep[] = {'\2',0};
3403 strcatW(data,sep);
3404 strcatW(data,feature->Feature_Parent);
3407 msi_reg_set_val_str( hkey, feature->Feature, data );
3408 msi_free(data);
3410 size = 0;
3411 if (feature->Feature_Parent)
3412 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3413 if (!absent)
3415 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3416 (LPBYTE)feature->Feature_Parent,size);
3418 else
3420 size += 2*sizeof(WCHAR);
3421 data = msi_alloc(size);
3422 data[0] = 0x6;
3423 data[1] = 0;
3424 if (feature->Feature_Parent)
3425 strcpyW( &data[1], feature->Feature_Parent );
3426 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3427 (LPBYTE)data,size);
3428 msi_free(data);
3431 /* the UI chunk */
3432 uirow = MSI_CreateRecord( 1 );
3433 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3434 ui_actiondata( package, szPublishFeatures, uirow);
3435 msiobj_release( &uirow->hdr );
3436 /* FIXME: call ui_progress? */
3439 end:
3440 RegCloseKey(hkey);
3441 RegCloseKey(hukey);
3442 return rc;
3445 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3447 static const WCHAR installerPathFmt[] = {
3448 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3449 static const WCHAR fmt[] = {
3450 '%','s','\\',
3451 'I','n','s','t','a','l','l','e','r','\\',
3452 '%','x','.','m','s','i',0};
3453 static const WCHAR szOriginalDatabase[] =
3454 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3455 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3456 INT num, start;
3457 LPWSTR msiFilePath;
3458 BOOL r;
3460 /* copy the package locally */
3461 num = GetTickCount() & 0xffff;
3462 if (!num)
3463 num = 1;
3464 start = num;
3465 GetWindowsDirectoryW( windir, MAX_PATH );
3466 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3469 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3470 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3471 if (handle != INVALID_HANDLE_VALUE)
3473 CloseHandle(handle);
3474 break;
3476 if (GetLastError() != ERROR_FILE_EXISTS &&
3477 GetLastError() != ERROR_SHARING_VIOLATION)
3478 break;
3479 if (!(++num & 0xffff)) num = 1;
3480 sprintfW(packagefile,fmt,num);
3481 } while (num != start);
3483 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3484 create_full_pathW(path);
3486 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3488 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3489 r = CopyFileW( msiFilePath, packagefile, FALSE);
3490 msi_free( msiFilePath );
3492 if (!r)
3494 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3495 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3496 return ERROR_FUNCTION_FAILED;
3499 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3500 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3501 return ERROR_SUCCESS;
3504 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3506 LPWSTR prop, val, key;
3507 static const LPCSTR propval[] = {
3508 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3509 "ARPCONTACT", "Contact",
3510 "ARPCOMMENTS", "Comments",
3511 "ProductName", "DisplayName",
3512 "ProductVersion", "DisplayVersion",
3513 "ARPHELPLINK", "HelpLink",
3514 "ARPHELPTELEPHONE", "HelpTelephone",
3515 "ARPINSTALLLOCATION", "InstallLocation",
3516 "SourceDir", "InstallSource",
3517 "Manufacturer", "Publisher",
3518 "ARPREADME", "Readme",
3519 "ARPSIZE", "Size",
3520 "ARPURLINFOABOUT", "URLInfoAbout",
3521 "ARPURLUPDATEINFO", "URLUpdateInfo",
3522 NULL,
3524 const LPCSTR *p = propval;
3526 while( *p )
3528 prop = strdupAtoW( *p++ );
3529 key = strdupAtoW( *p++ );
3530 val = msi_dup_property( package, prop );
3531 msi_reg_set_val_str( hkey, key, val );
3532 msi_free(val);
3533 msi_free(key);
3534 msi_free(prop);
3536 return ERROR_SUCCESS;
3539 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3541 HKEY hkey=0;
3542 LPWSTR buffer = NULL;
3543 UINT rc;
3544 DWORD size, langid;
3545 static const WCHAR szWindowsInstaller[] =
3546 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3547 static const WCHAR szUpgradeCode[] =
3548 {'U','p','g','r','a','d','e','C','o','d','e',0};
3549 static const WCHAR modpath_fmt[] =
3550 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3551 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3552 static const WCHAR szModifyPath[] =
3553 {'M','o','d','i','f','y','P','a','t','h',0};
3554 static const WCHAR szUninstallString[] =
3555 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3556 static const WCHAR szEstimatedSize[] =
3557 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3558 static const WCHAR szProductLanguage[] =
3559 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3560 static const WCHAR szProductVersion[] =
3561 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3563 SYSTEMTIME systime;
3564 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3565 LPWSTR upgrade_code;
3566 WCHAR szDate[9];
3568 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3569 if (rc != ERROR_SUCCESS)
3570 return rc;
3572 /* dump all the info i can grab */
3573 /* FIXME: Flesh out more information */
3575 msi_write_uninstall_property_vals( package, hkey );
3577 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3579 msi_make_package_local( package, hkey );
3581 /* do ModifyPath and UninstallString */
3582 size = deformat_string(package,modpath_fmt,&buffer);
3583 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3584 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3585 msi_free(buffer);
3587 /* FIXME: Write real Estimated Size when we have it */
3588 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3590 GetLocalTime(&systime);
3591 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3592 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3594 langid = msi_get_property_int( package, szProductLanguage, 0 );
3595 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3597 buffer = msi_dup_property( package, szProductVersion );
3598 if (buffer)
3600 DWORD verdword = build_version_dword(buffer);
3602 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3603 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3604 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3606 msi_free(buffer);
3608 /* Handle Upgrade Codes */
3609 upgrade_code = msi_dup_property( package, szUpgradeCode );
3610 if (upgrade_code)
3612 HKEY hkey2;
3613 WCHAR squashed[33];
3614 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3615 squash_guid(package->ProductCode,squashed);
3616 msi_reg_set_val_str( hkey2, squashed, NULL );
3617 RegCloseKey(hkey2);
3618 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3619 squash_guid(package->ProductCode,squashed);
3620 msi_reg_set_val_str( hkey2, squashed, NULL );
3621 RegCloseKey(hkey2);
3623 msi_free(upgrade_code);
3626 RegCloseKey(hkey);
3628 /* FIXME: call ui_actiondata */
3630 return ERROR_SUCCESS;
3633 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3635 return execute_script(package,INSTALL_SCRIPT);
3638 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3640 UINT rc;
3642 /* turn off scheduleing */
3643 package->script->CurrentlyScripting= FALSE;
3645 /* first do the same as an InstallExecute */
3646 rc = ACTION_InstallExecute(package);
3647 if (rc != ERROR_SUCCESS)
3648 return rc;
3650 /* then handle Commit Actions */
3651 rc = execute_script(package,COMMIT_SCRIPT);
3653 return rc;
3656 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3658 static const WCHAR RunOnce[] = {
3659 'S','o','f','t','w','a','r','e','\\',
3660 'M','i','c','r','o','s','o','f','t','\\',
3661 'W','i','n','d','o','w','s','\\',
3662 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3663 'R','u','n','O','n','c','e',0};
3664 static const WCHAR InstallRunOnce[] = {
3665 'S','o','f','t','w','a','r','e','\\',
3666 'M','i','c','r','o','s','o','f','t','\\',
3667 'W','i','n','d','o','w','s','\\',
3668 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3669 'I','n','s','t','a','l','l','e','r','\\',
3670 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3672 static const WCHAR msiexec_fmt[] = {
3673 '%','s',
3674 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3675 '\"','%','s','\"',0};
3676 static const WCHAR install_fmt[] = {
3677 '/','I',' ','\"','%','s','\"',' ',
3678 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3679 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3680 WCHAR buffer[256], sysdir[MAX_PATH];
3681 HKEY hkey;
3682 WCHAR squished_pc[100];
3684 squash_guid(package->ProductCode,squished_pc);
3686 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3687 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3688 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3689 squished_pc);
3691 msi_reg_set_val_str( hkey, squished_pc, buffer );
3692 RegCloseKey(hkey);
3694 TRACE("Reboot command %s\n",debugstr_w(buffer));
3696 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3697 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3699 msi_reg_set_val_str( hkey, squished_pc, buffer );
3700 RegCloseKey(hkey);
3702 return ERROR_INSTALL_SUSPEND;
3705 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3707 DWORD attrib;
3708 UINT rc;
3710 * we are currently doing what should be done here in the top level Install
3711 * however for Adminastrative and uninstalls this step will be needed
3713 if (!package->PackagePath)
3714 return ERROR_SUCCESS;
3716 attrib = GetFileAttributesW(package->PackagePath);
3717 if (attrib == INVALID_FILE_ATTRIBUTES)
3719 LPWSTR prompt;
3720 LPWSTR msg;
3721 DWORD size = 0;
3723 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3724 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3725 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3726 if (rc == ERROR_MORE_DATA)
3728 prompt = msi_alloc(size * sizeof(WCHAR));
3729 MsiSourceListGetInfoW(package->ProductCode, NULL,
3730 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3731 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3733 else
3734 prompt = strdupW(package->PackagePath);
3736 msg = generate_error_string(package,1302,1,prompt);
3737 while(attrib == INVALID_FILE_ATTRIBUTES)
3739 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3740 if (rc == IDCANCEL)
3742 rc = ERROR_INSTALL_USEREXIT;
3743 break;
3745 attrib = GetFileAttributesW(package->PackagePath);
3747 msi_free(prompt);
3748 rc = ERROR_SUCCESS;
3750 else
3751 return ERROR_SUCCESS;
3753 return rc;
3756 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3758 HKEY hkey=0;
3759 LPWSTR buffer;
3760 LPWSTR productid;
3761 UINT rc,i;
3763 static const WCHAR szPropKeys[][80] =
3765 {'P','r','o','d','u','c','t','I','D',0},
3766 {'U','S','E','R','N','A','M','E',0},
3767 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3768 {0},
3771 static const WCHAR szRegKeys[][80] =
3773 {'P','r','o','d','u','c','t','I','D',0},
3774 {'R','e','g','O','w','n','e','r',0},
3775 {'R','e','g','C','o','m','p','a','n','y',0},
3776 {0},
3779 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3780 if (!productid)
3781 return ERROR_SUCCESS;
3783 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3784 if (rc != ERROR_SUCCESS)
3785 goto end;
3787 for( i = 0; szPropKeys[i][0]; i++ )
3789 buffer = msi_dup_property( package, szPropKeys[i] );
3790 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3791 msi_free( buffer );
3794 end:
3795 msi_free(productid);
3796 RegCloseKey(hkey);
3798 /* FIXME: call ui_actiondata */
3800 return ERROR_SUCCESS;
3804 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3806 UINT rc;
3808 package->script->InWhatSequence |= SEQUENCE_EXEC;
3809 rc = ACTION_ProcessExecSequence(package,FALSE);
3810 return rc;
3815 * Code based off of code located here
3816 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3818 * Using string index 4 (full font name) instead of 1 (family name)
3820 static LPWSTR load_ttfname_from(LPCWSTR filename)
3822 HANDLE handle;
3823 LPWSTR ret = NULL;
3824 int i;
3826 typedef struct _tagTT_OFFSET_TABLE{
3827 USHORT uMajorVersion;
3828 USHORT uMinorVersion;
3829 USHORT uNumOfTables;
3830 USHORT uSearchRange;
3831 USHORT uEntrySelector;
3832 USHORT uRangeShift;
3833 }TT_OFFSET_TABLE;
3835 typedef struct _tagTT_TABLE_DIRECTORY{
3836 char szTag[4]; /* table name */
3837 ULONG uCheckSum; /* Check sum */
3838 ULONG uOffset; /* Offset from beginning of file */
3839 ULONG uLength; /* length of the table in bytes */
3840 }TT_TABLE_DIRECTORY;
3842 typedef struct _tagTT_NAME_TABLE_HEADER{
3843 USHORT uFSelector; /* format selector. Always 0 */
3844 USHORT uNRCount; /* Name Records count */
3845 USHORT uStorageOffset; /* Offset for strings storage,
3846 * from start of the table */
3847 }TT_NAME_TABLE_HEADER;
3849 typedef struct _tagTT_NAME_RECORD{
3850 USHORT uPlatformID;
3851 USHORT uEncodingID;
3852 USHORT uLanguageID;
3853 USHORT uNameID;
3854 USHORT uStringLength;
3855 USHORT uStringOffset; /* from start of storage area */
3856 }TT_NAME_RECORD;
3858 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3859 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3861 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3862 FILE_ATTRIBUTE_NORMAL, 0 );
3863 if (handle != INVALID_HANDLE_VALUE)
3865 TT_TABLE_DIRECTORY tblDir;
3866 BOOL bFound = FALSE;
3867 TT_OFFSET_TABLE ttOffsetTable;
3868 DWORD dwRead;
3870 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3871 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3872 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3873 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3875 if (ttOffsetTable.uMajorVersion != 1 ||
3876 ttOffsetTable.uMinorVersion != 0)
3877 return NULL;
3879 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3881 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3882 if (strncmp(tblDir.szTag,"name",4)==0)
3884 bFound = TRUE;
3885 tblDir.uLength = SWAPLONG(tblDir.uLength);
3886 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3887 break;
3891 if (bFound)
3893 TT_NAME_TABLE_HEADER ttNTHeader;
3894 TT_NAME_RECORD ttRecord;
3896 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3897 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3898 &dwRead,NULL);
3900 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3901 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3902 bFound = FALSE;
3903 for(i=0; i<ttNTHeader.uNRCount; i++)
3905 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3906 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3907 /* 4 is the Full Font Name */
3908 if(ttRecord.uNameID == 4)
3910 int nPos;
3911 LPSTR buf;
3912 static LPCSTR tt = " (TrueType)";
3914 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3915 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3916 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3917 SetFilePointer(handle, tblDir.uOffset +
3918 ttRecord.uStringOffset +
3919 ttNTHeader.uStorageOffset,
3920 NULL, FILE_BEGIN);
3921 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3922 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3923 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3924 if (strlen(buf) > 0)
3926 strcat(buf,tt);
3927 ret = strdupAtoW(buf);
3928 msi_free(buf);
3929 break;
3932 msi_free(buf);
3933 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3937 CloseHandle(handle);
3939 else
3940 ERR("Unable to open font file %s\n", debugstr_w(filename));
3942 TRACE("Returning fontname %s\n",debugstr_w(ret));
3943 return ret;
3946 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3948 MSIPACKAGE *package = (MSIPACKAGE*)param;
3949 LPWSTR name;
3950 LPCWSTR filename;
3951 MSIFILE *file;
3952 static const WCHAR regfont1[] =
3953 {'S','o','f','t','w','a','r','e','\\',
3954 'M','i','c','r','o','s','o','f','t','\\',
3955 'W','i','n','d','o','w','s',' ','N','T','\\',
3956 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3957 'F','o','n','t','s',0};
3958 static const WCHAR regfont2[] =
3959 {'S','o','f','t','w','a','r','e','\\',
3960 'M','i','c','r','o','s','o','f','t','\\',
3961 'W','i','n','d','o','w','s','\\',
3962 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3963 'F','o','n','t','s',0};
3964 HKEY hkey1;
3965 HKEY hkey2;
3966 MSIRECORD *uirow;
3967 LPWSTR uipath, p;
3969 filename = MSI_RecordGetString( row, 1 );
3970 file = get_loaded_file( package, filename );
3971 if (!file)
3973 ERR("Unable to load file\n");
3974 return ERROR_SUCCESS;
3977 /* check to make sure that component is installed */
3978 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3980 TRACE("Skipping: Component not scheduled for install\n");
3981 return ERROR_SUCCESS;
3984 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3985 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3987 if (MSI_RecordIsNull(row,2))
3988 name = load_ttfname_from( file->TargetPath );
3989 else
3990 name = msi_dup_record_field(row,2);
3992 if (name)
3994 msi_reg_set_val_str( hkey1, name, file->FileName );
3995 msi_reg_set_val_str( hkey2, name, file->FileName );
3998 msi_free(name);
3999 RegCloseKey(hkey1);
4000 RegCloseKey(hkey2);
4002 /* the UI chunk */
4003 uirow = MSI_CreateRecord( 1 );
4004 uipath = strdupW( file->TargetPath );
4005 p = strrchrW(uipath,'\\');
4006 if (p) p++;
4007 else p = uipath;
4008 MSI_RecordSetStringW( uirow, 1, p );
4009 ui_actiondata( package, szRegisterFonts, uirow);
4010 msiobj_release( &uirow->hdr );
4011 msi_free( uipath );
4012 /* FIXME: call ui_progress? */
4014 return ERROR_SUCCESS;
4017 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4019 UINT rc;
4020 MSIQUERY * view;
4021 static const WCHAR ExecSeqQuery[] =
4022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4023 '`','F','o','n','t','`',0};
4025 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4026 if (rc != ERROR_SUCCESS)
4028 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4029 return ERROR_SUCCESS;
4032 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4033 msiobj_release(&view->hdr);
4035 return ERROR_SUCCESS;
4038 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4040 MSIPACKAGE *package = (MSIPACKAGE*)param;
4041 LPCWSTR compgroupid=NULL;
4042 LPCWSTR feature=NULL;
4043 LPCWSTR text = NULL;
4044 LPCWSTR qualifier = NULL;
4045 LPCWSTR component = NULL;
4046 LPWSTR advertise = NULL;
4047 LPWSTR output = NULL;
4048 HKEY hkey;
4049 UINT rc = ERROR_SUCCESS;
4050 MSICOMPONENT *comp;
4051 DWORD sz = 0;
4052 MSIRECORD *uirow;
4054 component = MSI_RecordGetString(rec,3);
4055 comp = get_loaded_component(package,component);
4057 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4058 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4059 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4061 TRACE("Skipping: Component %s not scheduled for install\n",
4062 debugstr_w(component));
4064 return ERROR_SUCCESS;
4067 compgroupid = MSI_RecordGetString(rec,1);
4068 qualifier = MSI_RecordGetString(rec,2);
4070 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4071 if (rc != ERROR_SUCCESS)
4072 goto end;
4074 text = MSI_RecordGetString(rec,4);
4075 feature = MSI_RecordGetString(rec,5);
4077 advertise = create_component_advertise_string(package, comp, feature);
4079 sz = strlenW(advertise);
4081 if (text)
4082 sz += lstrlenW(text);
4084 sz+=3;
4085 sz *= sizeof(WCHAR);
4087 output = msi_alloc(sz);
4088 memset(output,0,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 struct _actions StandardActions[] = {
4284 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4285 { szAppSearch, ACTION_AppSearch },
4286 { szBindImage, ACTION_BindImage },
4287 { szCCPSearch, ACTION_CCPSearch},
4288 { szCostFinalize, ACTION_CostFinalize },
4289 { szCostInitialize, ACTION_CostInitialize },
4290 { szCreateFolders, ACTION_CreateFolders },
4291 { szCreateShortcuts, ACTION_CreateShortcuts },
4292 { szDeleteServices, ACTION_DeleteServices },
4293 { szDisableRollback, NULL},
4294 { szDuplicateFiles, ACTION_DuplicateFiles },
4295 { szExecuteAction, ACTION_ExecuteAction },
4296 { szFileCost, ACTION_FileCost },
4297 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4298 { szForceReboot, ACTION_ForceReboot },
4299 { szInstallAdminPackage, NULL},
4300 { szInstallExecute, ACTION_InstallExecute },
4301 { szInstallExecuteAgain, ACTION_InstallExecute },
4302 { szInstallFiles, ACTION_InstallFiles},
4303 { szInstallFinalize, ACTION_InstallFinalize },
4304 { szInstallInitialize, ACTION_InstallInitialize },
4305 { szInstallSFPCatalogFile, NULL},
4306 { szInstallValidate, ACTION_InstallValidate },
4307 { szIsolateComponents, ACTION_IsolateComponents },
4308 { szLaunchConditions, ACTION_LaunchConditions },
4309 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4310 { szMoveFiles, ACTION_MoveFiles },
4311 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4312 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4313 { szInstallODBC, NULL},
4314 { szInstallServices, ACTION_InstallServices },
4315 { szPatchFiles, ACTION_PatchFiles },
4316 { szProcessComponents, ACTION_ProcessComponents },
4317 { szPublishComponents, ACTION_PublishComponents },
4318 { szPublishFeatures, ACTION_PublishFeatures },
4319 { szPublishProduct, ACTION_PublishProduct },
4320 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4321 { szRegisterComPlus, NULL},
4322 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4323 { szRegisterFonts, ACTION_RegisterFonts },
4324 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4325 { szRegisterProduct, ACTION_RegisterProduct },
4326 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4327 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4328 { szRegisterUser, ACTION_RegisterUser},
4329 { szRemoveDuplicateFiles, NULL},
4330 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4331 { szRemoveExistingProducts, NULL},
4332 { szRemoveFiles, ACTION_RemoveFiles},
4333 { szRemoveFolders, NULL},
4334 { szRemoveIniValues, ACTION_RemoveIniValues },
4335 { szRemoveODBC, NULL},
4336 { szRemoveRegistryValues, NULL},
4337 { szRemoveShortcuts, NULL},
4338 { szResolveSource, ACTION_ResolveSource},
4339 { szRMCCPSearch, ACTION_RMCCPSearch},
4340 { szScheduleReboot, NULL},
4341 { szSelfRegModules, ACTION_SelfRegModules },
4342 { szSelfUnregModules, ACTION_SelfUnregModules },
4343 { szSetODBCFolders, NULL},
4344 { szStartServices, ACTION_StartServices },
4345 { szStopServices, ACTION_StopServices },
4346 { szUnpublishComponents, NULL},
4347 { szUnpublishFeatures, NULL},
4348 { szUnregisterClassInfo, NULL},
4349 { szUnregisterComPlus, NULL},
4350 { szUnregisterExtensionInfo, NULL},
4351 { szUnregisterFonts, ACTION_UnregisterFonts },
4352 { szUnregisterMIMEInfo, NULL},
4353 { szUnregisterProgIdInfo, NULL},
4354 { szUnregisterTypeLibraries, NULL},
4355 { szValidateProductID, NULL},
4356 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4357 { szWriteIniValues, ACTION_WriteIniValues },
4358 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4359 { NULL, NULL},