msi: Change some FIXME messages to comments.
[wine/wine64.git] / dlls / msi / action.c
blob0a062ba091c1ed97c850ff7c81a3db70deb3eaf5
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 ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
252 static const WCHAR szActionText[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
254 MSIRECORD *row;
256 row = MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row,1,action);
258 ControlEvent_FireSubscribedEvent(package,szActionText, row);
259 msiobj_release(&row->hdr);
262 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
264 static const WCHAR template_s[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
266 '.',0};
267 static const WCHAR format[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
274 WCHAR message[1024];
275 WCHAR timet[0x100];
276 MSIRECORD * row = 0;
277 LPCWSTR ActionText;
278 LPWSTR deformated;
280 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
282 row = MSI_QueryGetRecord( package->db, Query_t, action );
283 if (!row)
284 return;
286 ActionText = MSI_RecordGetString(row,2);
287 deformat_string(package, ActionText, &deformated);
289 sprintfW(message,template_s,timet,action,deformated);
290 ce_actiontext(package, deformated);
291 msiobj_release(&row->hdr);
293 row = MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row,1,message);
296 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
297 msiobj_release(&row->hdr);
298 msi_free(deformated);
301 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
302 UINT rc)
304 MSIRECORD * row;
305 static const WCHAR template_s[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
307 '%','s', '.',0};
308 static const WCHAR template_e[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
311 '%','i','.',0};
312 static const WCHAR format[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
314 WCHAR message[1024];
315 WCHAR timet[0x100];
317 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
318 if (start)
319 sprintfW(message,template_s,timet,action);
320 else
321 sprintfW(message,template_e,timet,action,rc);
323 row = MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row,1,message);
326 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
327 msiobj_release(&row->hdr);
330 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
332 LPWSTR str = msi_dup_property( package, prop );
333 int val = str ? atoiW( str ) : def;
334 msi_free( str );
335 return val;
338 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
340 LPCWSTR ptr,ptr2;
341 BOOL quote;
342 DWORD len;
343 LPWSTR prop = NULL, val = NULL;
345 if (!szCommandLine)
346 return ERROR_SUCCESS;
348 ptr = szCommandLine;
350 while (*ptr)
352 if (*ptr==' ')
354 ptr++;
355 continue;
358 TRACE("Looking at %s\n",debugstr_w(ptr));
360 ptr2 = strchrW(ptr,'=');
361 if (!ptr2)
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
364 break;
367 quote = FALSE;
369 len = ptr2-ptr;
370 prop = msi_alloc((len+1)*sizeof(WCHAR));
371 memcpy(prop,ptr,len*sizeof(WCHAR));
372 prop[len]=0;
373 ptr2++;
375 len = 0;
376 ptr = ptr2;
377 while (*ptr && (quote || (!quote && *ptr!=' ')))
379 if (*ptr == '"')
380 quote = !quote;
381 ptr++;
382 len++;
385 if (*ptr2=='"')
387 ptr2++;
388 len -= 2;
390 val = msi_alloc((len+1)*sizeof(WCHAR));
391 memcpy(val,ptr2,len*sizeof(WCHAR));
392 val[len] = 0;
394 if (lstrlenW(prop) > 0)
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop), debugstr_w(val));
398 MSI_SetPropertyW(package,prop,val);
400 msi_free(val);
401 msi_free(prop);
404 return ERROR_SUCCESS;
408 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
410 LPWSTR p, *ret = NULL;
411 UINT count = 0;
413 if (!str)
414 return ret;
416 /* count the number of substrings */
417 for ( p = (LPWSTR)str, count = 0; p; count++ )
419 p = strchrW( p, sep );
420 if (p)
421 p++;
424 /* allocate space for an array of substring pointers and the substrings */
425 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
426 (lstrlenW(str)+1) * sizeof(WCHAR) );
427 if (!ret)
428 return ret;
430 /* copy the string and set the pointers */
431 p = (LPWSTR) &ret[count+1];
432 lstrcpyW( p, str );
433 for( count = 0; (ret[count] = p); count++ )
435 p = strchrW( p, sep );
436 if (p)
437 *p++ = 0;
440 return ret;
443 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
444 MSIDATABASE *patch_db, LPCWSTR name )
446 UINT ret = ERROR_FUNCTION_FAILED;
447 IStorage *stg = NULL;
448 HRESULT r;
450 TRACE("%p %s\n", package, debugstr_w(name) );
452 if (*name++ != ':')
454 ERR("expected a colon in %s\n", debugstr_w(name));
455 return ERROR_FUNCTION_FAILED;
458 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
459 if (SUCCEEDED(r))
461 ret = msi_table_apply_transform( package->db, stg );
462 IStorage_Release( stg );
463 ret = ERROR_SUCCESS;
465 else
466 ERR("failed to open substorage %s\n", debugstr_w(name));
468 return ret;
471 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
473 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list, *guids, product_id;
475 UINT i, ret = ERROR_FUNCTION_FAILED;
477 product_id = msi_dup_property( package, szProdID );
478 if (!product_id)
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS;
485 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
486 guids = msi_split_string( guid_list, ';' );
487 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
489 if (!lstrcmpW( guids[i], product_id ))
490 ret = ERROR_SUCCESS;
492 msi_free( guids );
493 msi_free( guid_list );
494 msi_free( product_id );
496 return ret;
499 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
501 MSISUMMARYINFO *si;
502 LPWSTR str, *substorage;
503 UINT i, r = ERROR_SUCCESS;
505 si = MSI_GetSummaryInformationW( patch_db, 0 );
506 if (!si)
507 return ERROR_FUNCTION_FAILED;
509 msi_check_patch_applicable( package, si );
511 /* enumerate the substorage */
512 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
513 substorage = msi_split_string( str, ';' );
514 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
515 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
516 msi_free( substorage );
517 msi_free( str );
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
521 msiobj_release( &si->hdr );
523 return r;
526 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
528 MSIDATABASE *patch_db = NULL;
529 UINT r;
531 TRACE("%p %s\n", package, debugstr_w( file ) );
533 /* FIXME:
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
538 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
539 if ( r != ERROR_SUCCESS )
541 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
542 return r;
545 msi_parse_patch_summary( package, patch_db );
546 msiobj_release( &patch_db->hdr );
548 return ERROR_SUCCESS;
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT msi_apply_patches( MSIPACKAGE *package )
554 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list, *patches;
556 UINT i, r = ERROR_SUCCESS;
558 patch_list = msi_dup_property( package, szPatch );
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
562 patches = msi_split_string( patch_list, ';' );
563 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
564 r = msi_apply_patch_package( package, patches[i] );
566 msi_free( patches );
567 msi_free( patch_list );
569 return r;
572 /****************************************************
573 * TOP level entry points
574 *****************************************************/
576 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
577 LPCWSTR szCommandLine )
579 UINT rc;
580 BOOL ui = FALSE;
581 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
582 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
583 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
585 MSI_SetPropertyW(package, szAction, szInstall);
587 package->script = msi_alloc(sizeof(MSISCRIPT));
588 memset(package->script,0,sizeof(MSISCRIPT));
590 package->script->InWhatSequence = SEQUENCE_INSTALL;
592 if (szPackagePath)
594 LPWSTR p, check, path;
596 package->PackagePath = strdupW(szPackagePath);
597 path = strdupW(szPackagePath);
598 p = strrchrW(path,'\\');
599 if (p)
601 p++;
602 *p=0;
604 else
606 msi_free(path);
607 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
608 GetCurrentDirectoryW(MAX_PATH,path);
609 strcatW(path,cszbs);
612 check = msi_dup_property( package, cszSourceDir );
613 if (!check)
614 MSI_SetPropertyW(package, cszSourceDir, path);
615 msi_free(check);
616 msi_free(path);
619 msi_parse_command_line( package, szCommandLine );
621 msi_apply_patches( package );
623 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
625 package->script->InWhatSequence |= SEQUENCE_UI;
626 rc = ACTION_ProcessUISequence(package);
627 ui = TRUE;
628 if (rc == ERROR_SUCCESS)
630 package->script->InWhatSequence |= SEQUENCE_EXEC;
631 rc = ACTION_ProcessExecSequence(package,TRUE);
634 else
635 rc = ACTION_ProcessExecSequence(package,FALSE);
637 if (rc == -1)
639 /* install was halted but should be considered a success */
640 rc = ERROR_SUCCESS;
643 package->script->CurrentlyScripting= FALSE;
645 /* process the ending type action */
646 if (rc == ERROR_SUCCESS)
647 ACTION_PerformActionSequence(package,-1,ui);
648 else if (rc == ERROR_INSTALL_USEREXIT)
649 ACTION_PerformActionSequence(package,-2,ui);
650 else if (rc == ERROR_INSTALL_SUSPEND)
651 ACTION_PerformActionSequence(package,-4,ui);
652 else /* failed */
653 ACTION_PerformActionSequence(package,-3,ui);
655 /* finish up running custom actions */
656 ACTION_FinishCustomActions(package);
658 return rc;
661 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
663 UINT rc = ERROR_SUCCESS;
664 MSIRECORD * row = 0;
665 static const WCHAR ExecSeqQuery[] =
666 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
667 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
668 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
669 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
671 static const WCHAR UISeqQuery[] =
672 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
673 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
674 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
675 ' ', '=',' ','%','i',0};
677 if (UI)
678 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
679 else
680 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
682 if (row)
684 LPCWSTR action, cond;
686 TRACE("Running the actions\n");
688 /* check conditions */
689 cond = MSI_RecordGetString(row,2);
690 if (cond)
692 /* this is a hack to skip errors in the condition code */
693 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
694 goto end;
697 action = MSI_RecordGetString(row,1);
698 if (!action)
700 ERR("failed to fetch action\n");
701 rc = ERROR_FUNCTION_FAILED;
702 goto end;
705 if (UI)
706 rc = ACTION_PerformUIAction(package,action);
707 else
708 rc = ACTION_PerformAction(package,action,FALSE);
709 end:
710 msiobj_release(&row->hdr);
712 else
713 rc = ERROR_SUCCESS;
715 return rc;
718 typedef struct {
719 MSIPACKAGE* package;
720 BOOL UI;
721 } iterate_action_param;
723 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
725 iterate_action_param *iap= (iterate_action_param*)param;
726 UINT rc;
727 LPCWSTR cond, action;
729 action = MSI_RecordGetString(row,1);
730 if (!action)
732 ERR("Error is retrieving action name\n");
733 return ERROR_FUNCTION_FAILED;
736 /* check conditions */
737 cond = MSI_RecordGetString(row,2);
738 if (cond)
740 /* this is a hack to skip errors in the condition code */
741 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
743 TRACE("Skipping action: %s (condition is false)\n",
744 debugstr_w(action));
745 return ERROR_SUCCESS;
749 if (iap->UI)
750 rc = ACTION_PerformUIAction(iap->package,action);
751 else
752 rc = ACTION_PerformAction(iap->package,action,FALSE);
754 msi_dialog_check_messages( NULL );
756 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
757 rc = iap->package->CurrentInstallState;
759 if (rc == ERROR_FUNCTION_NOT_CALLED)
760 rc = ERROR_SUCCESS;
762 if (rc != ERROR_SUCCESS)
763 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
765 return rc;
768 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
770 MSIQUERY * view;
771 UINT r;
772 static const WCHAR query[] =
773 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
774 '`','%','s','`',
775 ' ','W','H','E','R','E',' ',
776 '`','S','e','q','u','e','n','c','e','`',' ',
777 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
778 '`','S','e','q','u','e','n','c','e','`',0};
779 iterate_action_param iap;
782 * FIXME: probably should be checking UILevel in the
783 * ACTION_PerformUIAction/ACTION_PerformAction
784 * rather than saving the UI level here. Those
785 * two functions can be merged too.
787 iap.package = package;
788 iap.UI = TRUE;
790 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
792 r = MSI_OpenQuery( package->db, &view, query, szTable );
793 if (r == ERROR_SUCCESS)
795 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
796 msiobj_release(&view->hdr);
799 return r;
802 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
804 MSIQUERY * view;
805 UINT rc;
806 static const WCHAR ExecSeqQuery[] =
807 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
808 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
809 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
810 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
811 'O','R','D','E','R',' ', 'B','Y',' ',
812 '`','S','e','q','u','e','n','c','e','`',0 };
813 MSIRECORD * row = 0;
814 static const WCHAR IVQuery[] =
815 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
816 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
817 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
818 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
819 ' ','\'', 'I','n','s','t','a','l','l',
820 'V','a','l','i','d','a','t','e','\'', 0};
821 INT seq = 0;
822 iterate_action_param iap;
824 iap.package = package;
825 iap.UI = FALSE;
827 if (package->script->ExecuteSequenceRun)
829 TRACE("Execute Sequence already Run\n");
830 return ERROR_SUCCESS;
833 package->script->ExecuteSequenceRun = TRUE;
835 /* get the sequence number */
836 if (UIran)
838 row = MSI_QueryGetRecord(package->db, IVQuery);
839 if( !row )
840 return ERROR_FUNCTION_FAILED;
841 seq = MSI_RecordGetInteger(row,1);
842 msiobj_release(&row->hdr);
845 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
846 if (rc == ERROR_SUCCESS)
848 TRACE("Running the actions\n");
850 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
851 msiobj_release(&view->hdr);
854 return rc;
857 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
859 MSIQUERY * view;
860 UINT rc;
861 static const WCHAR ExecSeqQuery [] =
862 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
863 '`','I','n','s','t','a','l','l',
864 'U','I','S','e','q','u','e','n','c','e','`',
865 ' ','W','H','E','R','E',' ',
866 '`','S','e','q','u','e','n','c','e','`',' ',
867 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
868 '`','S','e','q','u','e','n','c','e','`',0};
869 iterate_action_param iap;
871 iap.package = package;
872 iap.UI = TRUE;
874 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
876 if (rc == ERROR_SUCCESS)
878 TRACE("Running the actions\n");
880 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
881 msiobj_release(&view->hdr);
884 return rc;
887 /********************************************************
888 * ACTION helper functions and functions that perform the actions
889 *******************************************************/
890 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
891 UINT* rc, BOOL force )
893 BOOL ret = FALSE;
894 BOOL run = force;
895 int i;
897 if (!package)
899 ERR("package was null!\n");
900 return FALSE;
903 if (!run && !package->script->CurrentlyScripting)
904 run = TRUE;
906 if (!run)
908 if (strcmpW(action,szInstallFinalize) == 0 ||
909 strcmpW(action,szInstallExecute) == 0 ||
910 strcmpW(action,szInstallExecuteAgain) == 0)
911 run = TRUE;
914 i = 0;
915 while (StandardActions[i].action != NULL)
917 if (strcmpW(StandardActions[i].action, action)==0)
919 if (!run)
921 ui_actioninfo(package, action, TRUE, 0);
922 *rc = schedule_action(package,INSTALL_SCRIPT,action);
923 ui_actioninfo(package, action, FALSE, *rc);
925 else
927 ui_actionstart(package, action);
928 if (StandardActions[i].handler)
930 *rc = StandardActions[i].handler(package);
932 else
934 FIXME("unhandled standard action %s\n",debugstr_w(action));
935 *rc = ERROR_SUCCESS;
938 ret = TRUE;
939 break;
941 i++;
943 return ret;
946 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
947 UINT* rc, BOOL force )
949 BOOL ret=FALSE;
950 UINT arc;
952 arc = ACTION_CustomAction(package,action, force);
954 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
956 *rc = arc;
957 ret = TRUE;
959 return ret;
963 * A lot of actions are really important even if they don't do anything
964 * explicit... Lots of properties are set at the beginning of the installation
965 * CostFinalize does a bunch of work to translate the directories and such
967 * But until I get write access to the database that is hard, so I am going to
968 * hack it to see if I can get something to run.
970 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
972 UINT rc = ERROR_SUCCESS;
973 BOOL handled;
975 TRACE("Performing action (%s)\n",debugstr_w(action));
977 handled = ACTION_HandleStandardAction(package, action, &rc, force);
979 if (!handled)
980 handled = ACTION_HandleCustomAction(package, action, &rc, force);
982 if (!handled)
984 FIXME("unhandled msi action %s\n",debugstr_w(action));
985 rc = ERROR_FUNCTION_NOT_CALLED;
988 return rc;
991 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
993 UINT rc = ERROR_SUCCESS;
994 BOOL handled = FALSE;
996 TRACE("Performing action (%s)\n",debugstr_w(action));
998 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1000 if (!handled)
1001 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1003 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1004 handled = TRUE;
1006 if (!handled)
1008 FIXME("unhandled msi action %s\n",debugstr_w(action));
1009 rc = ERROR_FUNCTION_NOT_CALLED;
1012 return rc;
1017 * Actual Action Handlers
1020 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1022 MSIPACKAGE *package = (MSIPACKAGE*)param;
1023 LPCWSTR dir;
1024 LPWSTR full_path;
1025 MSIRECORD *uirow;
1026 MSIFOLDER *folder;
1028 dir = MSI_RecordGetString(row,1);
1029 if (!dir)
1031 ERR("Unable to get folder id\n");
1032 return ERROR_SUCCESS;
1035 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1036 if (!full_path)
1038 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1039 return ERROR_SUCCESS;
1042 TRACE("Folder is %s\n",debugstr_w(full_path));
1044 /* UI stuff */
1045 uirow = MSI_CreateRecord(1);
1046 MSI_RecordSetStringW(uirow,1,full_path);
1047 ui_actiondata(package,szCreateFolders,uirow);
1048 msiobj_release( &uirow->hdr );
1050 if (folder->State == 0)
1051 create_full_pathW(full_path);
1053 folder->State = 3;
1055 msi_free(full_path);
1056 return ERROR_SUCCESS;
1059 /* FIXME: probably should merge this with the above function */
1060 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1062 UINT rc = ERROR_SUCCESS;
1063 MSIFOLDER *folder;
1064 LPWSTR install_path;
1066 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1067 if (!install_path)
1068 return ERROR_FUNCTION_FAILED;
1070 /* create the path */
1071 if (folder->State == 0)
1073 create_full_pathW(install_path);
1074 folder->State = 2;
1076 msi_free(install_path);
1078 return rc;
1081 UINT msi_create_component_directories( MSIPACKAGE *package )
1083 MSICOMPONENT *comp;
1085 /* create all the folders required by the components are going to install */
1086 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1088 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1089 continue;
1090 msi_create_directory( package, comp->Directory );
1093 return ERROR_SUCCESS;
1097 * Also we cannot enable/disable components either, so for now I am just going
1098 * to do all the directories for all the components.
1100 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1102 static const WCHAR ExecSeqQuery[] =
1103 {'S','E','L','E','C','T',' ',
1104 '`','D','i','r','e','c','t','o','r','y','_','`',
1105 ' ','F','R','O','M',' ',
1106 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1107 UINT rc;
1108 MSIQUERY *view;
1110 /* create all the empty folders specified in the CreateFolder table */
1111 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1112 if (rc != ERROR_SUCCESS)
1113 return ERROR_SUCCESS;
1115 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1116 msiobj_release(&view->hdr);
1118 msi_create_component_directories( package );
1120 return rc;
1123 static MSICOMPONENT* load_component( MSIRECORD * row )
1125 MSICOMPONENT *comp;
1127 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1128 if (!comp)
1129 return comp;
1131 /* fill in the data */
1132 comp->Component = msi_dup_record_field( row, 1 );
1134 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1136 comp->ComponentId = msi_dup_record_field( row, 2 );
1137 comp->Directory = msi_dup_record_field( row, 3 );
1138 comp->Attributes = MSI_RecordGetInteger(row,4);
1139 comp->Condition = msi_dup_record_field( row, 5 );
1140 comp->KeyPath = msi_dup_record_field( row, 6 );
1142 comp->Installed = INSTALLSTATE_ABSENT;
1143 comp->Action = INSTALLSTATE_UNKNOWN;
1144 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1146 comp->Enabled = TRUE;
1148 return comp;
1151 typedef struct {
1152 MSIPACKAGE *package;
1153 MSIFEATURE *feature;
1154 } _ilfs;
1156 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1158 ComponentList *cl;
1160 cl = msi_alloc( sizeof (*cl) );
1161 if ( !cl )
1162 return ERROR_NOT_ENOUGH_MEMORY;
1163 cl->component = comp;
1164 list_add_tail( &feature->Components, &cl->entry );
1166 return ERROR_SUCCESS;
1169 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1171 _ilfs* ilfs= (_ilfs*)param;
1172 MSIPACKAGE *package = ilfs->package;
1173 MSIFEATURE *feature = ilfs->feature;
1174 MSICOMPONENT *comp;
1176 comp = load_component( row );
1177 if (!comp)
1178 return ERROR_FUNCTION_FAILED;
1180 list_add_tail( &package->components, &comp->entry );
1181 add_feature_component( feature, comp );
1183 TRACE("Loaded new component %p\n", comp);
1185 return ERROR_SUCCESS;
1188 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1190 _ilfs* ilfs= (_ilfs*)param;
1191 LPCWSTR component;
1192 DWORD rc;
1193 MSICOMPONENT *comp;
1194 MSIQUERY * view;
1195 static const WCHAR Query[] =
1196 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1197 '`','C','o','m','p','o','n','e','n','t','`',' ',
1198 'W','H','E','R','E',' ',
1199 '`','C','o','m','p','o','n','e','n','t','`',' ',
1200 '=','\'','%','s','\'',0};
1202 component = MSI_RecordGetString(row,1);
1204 /* check to see if the component is already loaded */
1205 comp = get_loaded_component( ilfs->package, component );
1206 if (comp)
1208 TRACE("Component %s already loaded\n", debugstr_w(component) );
1209 add_feature_component( ilfs->feature, comp );
1210 return ERROR_SUCCESS;
1213 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1214 if (rc != ERROR_SUCCESS)
1215 return ERROR_SUCCESS;
1217 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1218 msiobj_release( &view->hdr );
1220 return ERROR_SUCCESS;
1223 static UINT load_feature(MSIRECORD * row, LPVOID param)
1225 MSIPACKAGE* package = (MSIPACKAGE*)param;
1226 MSIFEATURE* feature;
1227 static const WCHAR Query1[] =
1228 {'S','E','L','E','C','T',' ',
1229 '`','C','o','m','p','o','n','e','n','t','_','`',
1230 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1231 'C','o','m','p','o','n','e','n','t','s','`',' ',
1232 'W','H','E','R','E',' ',
1233 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1234 MSIQUERY * view;
1235 UINT rc;
1236 _ilfs ilfs;
1238 /* fill in the data */
1240 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1241 if (!feature)
1242 return ERROR_NOT_ENOUGH_MEMORY;
1244 list_init( &feature->Components );
1246 feature->Feature = msi_dup_record_field( row, 1 );
1248 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1250 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1251 feature->Title = msi_dup_record_field( row, 3 );
1252 feature->Description = msi_dup_record_field( row, 4 );
1254 if (!MSI_RecordIsNull(row,5))
1255 feature->Display = MSI_RecordGetInteger(row,5);
1257 feature->Level= MSI_RecordGetInteger(row,6);
1258 feature->Directory = msi_dup_record_field( row, 7 );
1259 feature->Attributes = MSI_RecordGetInteger(row,8);
1261 feature->Installed = INSTALLSTATE_ABSENT;
1262 feature->Action = INSTALLSTATE_UNKNOWN;
1263 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1265 list_add_tail( &package->features, &feature->entry );
1267 /* load feature components */
1269 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1270 if (rc != ERROR_SUCCESS)
1271 return ERROR_SUCCESS;
1273 ilfs.package = package;
1274 ilfs.feature = feature;
1276 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1277 msiobj_release(&view->hdr);
1279 return ERROR_SUCCESS;
1282 static UINT load_file(MSIRECORD *row, LPVOID param)
1284 MSIPACKAGE* package = (MSIPACKAGE*)param;
1285 LPCWSTR component;
1286 MSIFILE *file;
1288 /* fill in the data */
1290 file = msi_alloc_zero( sizeof (MSIFILE) );
1291 if (!file)
1292 return ERROR_NOT_ENOUGH_MEMORY;
1294 file->File = msi_dup_record_field( row, 1 );
1296 component = MSI_RecordGetString( row, 2 );
1297 file->Component = get_loaded_component( package, component );
1299 if (!file->Component)
1300 ERR("Unfound Component %s\n",debugstr_w(component));
1302 file->FileName = msi_dup_record_field( row, 3 );
1303 reduce_to_longfilename( file->FileName );
1305 file->ShortName = msi_dup_record_field( row, 3 );
1306 reduce_to_shortfilename( file->ShortName );
1308 file->FileSize = MSI_RecordGetInteger( row, 4 );
1309 file->Version = msi_dup_record_field( row, 5 );
1310 file->Language = msi_dup_record_field( row, 6 );
1311 file->Attributes = MSI_RecordGetInteger( row, 7 );
1312 file->Sequence = MSI_RecordGetInteger( row, 8 );
1314 file->state = msifs_invalid;
1316 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1318 list_add_tail( &package->files, &file->entry );
1320 return ERROR_SUCCESS;
1323 static UINT load_all_files(MSIPACKAGE *package)
1325 MSIQUERY * view;
1326 UINT rc;
1327 static const WCHAR Query[] =
1328 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1330 '`','S','e','q','u','e','n','c','e','`', 0};
1332 if (!package)
1333 return ERROR_INVALID_HANDLE;
1335 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1336 if (rc != ERROR_SUCCESS)
1337 return ERROR_SUCCESS;
1339 rc = MSI_IterateRecords(view, NULL, load_file, package);
1340 msiobj_release(&view->hdr);
1342 return ERROR_SUCCESS;
1347 * I am not doing any of the costing functionality yet.
1348 * Mostly looking at doing the Component and Feature loading
1350 * The native MSI does A LOT of modification to tables here. Mostly adding
1351 * a lot of temporary columns to the Feature and Component tables.
1353 * note: Native msi also tracks the short filename. But I am only going to
1354 * track the long ones. Also looking at this directory table
1355 * it appears that the directory table does not get the parents
1356 * resolved base on property only based on their entries in the
1357 * directory table.
1359 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1361 MSIQUERY * view;
1362 UINT rc;
1363 static const WCHAR Query_all[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','e','a','t','u','r','e','`',0};
1366 static const WCHAR szCosting[] =
1367 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1368 static const WCHAR szZero[] = { '0', 0 };
1370 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1371 return ERROR_SUCCESS;
1373 MSI_SetPropertyW(package, szCosting, szZero);
1374 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1376 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1377 if (rc != ERROR_SUCCESS)
1378 return rc;
1380 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1381 msiobj_release(&view->hdr);
1383 load_all_files(package);
1385 return ERROR_SUCCESS;
1388 static UINT execute_script(MSIPACKAGE *package, UINT script )
1390 int i;
1391 UINT rc = ERROR_SUCCESS;
1393 TRACE("Executing Script %i\n",script);
1395 for (i = 0; i < package->script->ActionCount[script]; i++)
1397 LPWSTR action;
1398 action = package->script->Actions[script][i];
1399 ui_actionstart(package, action);
1400 TRACE("Executing Action (%s)\n",debugstr_w(action));
1401 rc = ACTION_PerformAction(package, action, TRUE);
1402 msi_free(package->script->Actions[script][i]);
1403 if (rc != ERROR_SUCCESS)
1404 break;
1406 msi_free(package->script->Actions[script]);
1408 package->script->ActionCount[script] = 0;
1409 package->script->Actions[script] = NULL;
1410 return rc;
1413 static UINT ACTION_FileCost(MSIPACKAGE *package)
1415 return ERROR_SUCCESS;
1419 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1421 static const WCHAR Query[] =
1422 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1423 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1424 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1425 ' ','=',' ','\'','%','s','\'',
1427 LPWSTR ptargetdir, targetdir, srcdir;
1428 LPCWSTR parent;
1429 LPWSTR shortname = NULL;
1430 MSIRECORD * row = 0;
1431 MSIFOLDER *folder;
1433 TRACE("Looking for dir %s\n",debugstr_w(dir));
1435 folder = get_loaded_folder( package, dir );
1436 if (folder)
1437 return folder;
1439 TRACE("Working to load %s\n",debugstr_w(dir));
1441 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1442 if (!folder)
1443 return NULL;
1445 folder->Directory = strdupW(dir);
1447 row = MSI_QueryGetRecord(package->db, Query, dir);
1448 if (!row)
1449 return NULL;
1451 ptargetdir = targetdir = msi_dup_record_field(row,3);
1453 /* split src and target dir */
1454 if (strchrW(targetdir,':'))
1456 srcdir=strchrW(targetdir,':');
1457 *srcdir=0;
1458 srcdir ++;
1460 else
1461 srcdir=NULL;
1463 /* for now only pick long filename versions */
1464 if (strchrW(targetdir,'|'))
1466 shortname = targetdir;
1467 targetdir = strchrW(targetdir,'|');
1468 *targetdir = 0;
1469 targetdir ++;
1471 /* for the sourcedir pick the short filename */
1472 if (srcdir && strchrW(srcdir,'|'))
1474 LPWSTR p = strchrW(srcdir,'|');
1475 *p = 0;
1478 /* now check for root dirs */
1479 if (targetdir[0] == '.' && targetdir[1] == 0)
1480 targetdir = NULL;
1482 if (targetdir)
1484 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1485 msi_free( folder->TargetDefault);
1486 folder->TargetDefault = strdupW(targetdir);
1489 if (srcdir)
1490 folder->SourceDefault = strdupW(srcdir);
1491 else if (shortname)
1492 folder->SourceDefault = strdupW(shortname);
1493 else if (targetdir)
1494 folder->SourceDefault = strdupW(targetdir);
1495 msi_free(ptargetdir);
1496 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1498 parent = MSI_RecordGetString(row,2);
1499 if (parent)
1501 folder->Parent = load_folder( package, parent );
1502 if ( folder->Parent )
1503 TRACE("loaded parent %p %s\n", folder->Parent,
1504 debugstr_w(folder->Parent->Directory));
1505 else
1506 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1509 folder->Property = msi_dup_property( package, dir );
1511 msiobj_release(&row->hdr);
1513 list_add_tail( &package->folders, &folder->entry );
1515 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1517 return folder;
1520 /* scan for and update current install states */
1521 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1523 MSICOMPONENT *comp;
1524 MSIFEATURE *feature;
1526 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1528 INSTALLSTATE res;
1529 res = MsiGetComponentPathW( package->ProductCode,
1530 comp->ComponentId, NULL, NULL);
1531 if (res < 0)
1532 res = INSTALLSTATE_ABSENT;
1533 comp->Installed = res;
1536 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1538 ComponentList *cl;
1539 INSTALLSTATE res = -10;
1541 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1543 comp= cl->component;
1545 if (res == -10)
1546 res = comp->Installed;
1547 else
1549 if (res == comp->Installed)
1550 continue;
1552 if (res != comp->Installed)
1553 res = INSTALLSTATE_INCOMPLETE;
1556 feature->Installed = res;
1560 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1561 INSTALLSTATE state)
1563 static const WCHAR all[]={'A','L','L',0};
1564 LPWSTR override;
1565 MSIFEATURE *feature;
1567 override = msi_dup_property( package, property );
1568 if (!override)
1569 return FALSE;
1571 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1573 if (strcmpiW(override,all)==0)
1575 feature->ActionRequest= state;
1576 feature->Action = state;
1578 else
1580 LPWSTR ptr = override;
1581 LPWSTR ptr2 = strchrW(override,',');
1583 while (ptr)
1585 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1586 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1588 feature->ActionRequest= state;
1589 feature->Action = state;
1590 break;
1592 if (ptr2)
1594 ptr=ptr2+1;
1595 ptr2 = strchrW(ptr,',');
1597 else
1598 break;
1602 msi_free(override);
1604 return TRUE;
1607 static UINT SetFeatureStates(MSIPACKAGE *package)
1609 int install_level;
1610 static const WCHAR szlevel[] =
1611 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1612 static const WCHAR szAddLocal[] =
1613 {'A','D','D','L','O','C','A','L',0};
1614 static const WCHAR szRemove[] =
1615 {'R','E','M','O','V','E',0};
1616 static const WCHAR szReinstall[] =
1617 {'R','E','I','N','S','T','A','L','L',0};
1618 BOOL override = FALSE;
1619 MSICOMPONENT* component;
1620 MSIFEATURE *feature;
1623 /* I do not know if this is where it should happen.. but */
1625 TRACE("Checking Install Level\n");
1627 install_level = msi_get_property_int( package, szlevel, 1 );
1629 /* ok hereis the _real_ rub
1630 * all these activation/deactivation things happen in order and things
1631 * later on the list override things earlier on the list.
1632 * 1) INSTALLLEVEL processing
1633 * 2) ADDLOCAL
1634 * 3) REMOVE
1635 * 4) ADDSOURCE
1636 * 5) ADDDEFAULT
1637 * 6) REINSTALL
1638 * 7) COMPADDLOCAL
1639 * 8) COMPADDSOURCE
1640 * 9) FILEADDLOCAL
1641 * 10) FILEADDSOURCE
1642 * 11) FILEADDDEFAULT
1643 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1644 * ignored for all the features. seems strange, especially since it is not
1645 * documented anywhere, but it is how it works.
1647 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1648 * REMOVE are the big ones, since we don't handle administrative installs
1649 * yet anyway.
1651 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1652 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1653 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1655 if (!override)
1657 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1659 BOOL feature_state = ((feature->Level > 0) &&
1660 (feature->Level <= install_level));
1662 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1664 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1666 feature->ActionRequest = INSTALLSTATE_SOURCE;
1667 feature->Action = INSTALLSTATE_SOURCE;
1669 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1671 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1672 feature->Action = INSTALLSTATE_ADVERTISED;
1674 else
1676 feature->ActionRequest = INSTALLSTATE_LOCAL;
1677 feature->Action = INSTALLSTATE_LOCAL;
1682 else
1684 /* set the Preselected Property */
1685 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1686 static const WCHAR szOne[] = { '1', 0 };
1688 MSI_SetPropertyW(package,szPreselected,szOne);
1692 * now we want to enable or disable components base on feature
1695 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1697 ComponentList *cl;
1699 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1700 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1701 feature->ActionRequest);
1703 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1705 component = cl->component;
1707 if (!component->Enabled)
1709 component->Action = INSTALLSTATE_UNKNOWN;
1710 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1712 else
1714 if (feature->Action == INSTALLSTATE_LOCAL)
1716 component->Action = INSTALLSTATE_LOCAL;
1717 component->ActionRequest = INSTALLSTATE_LOCAL;
1719 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1721 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1722 (component->Action == INSTALLSTATE_ABSENT) ||
1723 (component->Action == INSTALLSTATE_ADVERTISED))
1726 component->Action = INSTALLSTATE_SOURCE;
1727 component->ActionRequest = INSTALLSTATE_SOURCE;
1730 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1732 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1733 (component->Action == INSTALLSTATE_ABSENT))
1736 component->Action = INSTALLSTATE_ADVERTISED;
1737 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1740 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1742 if (component->Action == INSTALLSTATE_UNKNOWN)
1744 component->Action = INSTALLSTATE_ABSENT;
1745 component->ActionRequest = INSTALLSTATE_ABSENT;
1752 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1754 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1755 debugstr_w(component->Component), component->Installed,
1756 component->Action, component->ActionRequest);
1760 return ERROR_SUCCESS;
1763 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1765 MSIPACKAGE *package = (MSIPACKAGE*)param;
1766 LPCWSTR name;
1767 LPWSTR path;
1769 name = MSI_RecordGetString(row,1);
1771 /* This helper function now does ALL the work */
1772 TRACE("Dir %s ...\n",debugstr_w(name));
1773 load_folder(package,name);
1774 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1775 TRACE("resolves to %s\n",debugstr_w(path));
1776 msi_free(path);
1778 return ERROR_SUCCESS;
1781 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1783 MSIPACKAGE *package = (MSIPACKAGE*)param;
1784 LPCWSTR name;
1785 MSIFEATURE *feature;
1787 name = MSI_RecordGetString( row, 1 );
1789 feature = get_loaded_feature( package, name );
1790 if (!feature)
1791 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1792 else
1794 LPCWSTR Condition;
1795 Condition = MSI_RecordGetString(row,3);
1797 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1799 int level = MSI_RecordGetInteger(row,2);
1800 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1801 feature->Level = level;
1804 return ERROR_SUCCESS;
1809 * A lot is done in this function aside from just the costing.
1810 * The costing needs to be implemented at some point but for now I am going
1811 * to focus on the directory building
1814 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1816 static const WCHAR ExecSeqQuery[] =
1817 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1818 '`','D','i','r','e','c','t','o','r','y','`',0};
1819 static const WCHAR ConditionQuery[] =
1820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1821 '`','C','o','n','d','i','t','i','o','n','`',0};
1822 static const WCHAR szCosting[] =
1823 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1824 static const WCHAR szlevel[] =
1825 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1826 static const WCHAR szOne[] = { '1', 0 };
1827 MSICOMPONENT *comp;
1828 MSIFILE *file;
1829 UINT rc;
1830 MSIQUERY * view;
1831 LPWSTR level;
1833 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1834 return ERROR_SUCCESS;
1836 TRACE("Building Directory properties\n");
1838 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1839 if (rc == ERROR_SUCCESS)
1841 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1842 package);
1843 msiobj_release(&view->hdr);
1846 TRACE("File calculations\n");
1848 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1850 MSICOMPONENT* comp = file->Component;
1851 LPWSTR p;
1853 if (!comp)
1854 continue;
1856 /* calculate target */
1857 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1859 msi_free(file->TargetPath);
1861 TRACE("file %s is named %s\n",
1862 debugstr_w(file->File),debugstr_w(file->FileName));
1864 file->TargetPath = build_directory_name(2, p, file->FileName);
1866 msi_free(p);
1868 TRACE("file %s resolves to %s\n",
1869 debugstr_w(file->File),debugstr_w(file->TargetPath));
1871 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1873 file->state = msifs_missing;
1874 comp->Cost += file->FileSize;
1875 continue;
1878 if (file->Version)
1880 DWORD handle;
1881 DWORD versize;
1882 UINT sz;
1883 LPVOID version;
1884 static WCHAR name[] = {'\\',0};
1885 static const WCHAR name_fmt[] =
1886 {'%','u','.','%','u','.','%','u','.','%','u',0};
1887 WCHAR filever[0x100];
1888 VS_FIXEDFILEINFO *lpVer;
1890 TRACE("Version comparison..\n");
1891 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1892 version = msi_alloc(versize);
1893 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1895 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1897 sprintfW(filever,name_fmt,
1898 HIWORD(lpVer->dwFileVersionMS),
1899 LOWORD(lpVer->dwFileVersionMS),
1900 HIWORD(lpVer->dwFileVersionLS),
1901 LOWORD(lpVer->dwFileVersionLS));
1903 TRACE("new %s old %s\n", debugstr_w(file->Version),
1904 debugstr_w(filever));
1905 if (strcmpiW(filever,file->Version)<0)
1907 file->state = msifs_overwrite;
1908 /* FIXME: cost should be diff in size */
1909 comp->Cost += file->FileSize;
1911 else
1912 file->state = msifs_present;
1913 msi_free(version);
1915 else
1916 file->state = msifs_present;
1919 TRACE("Evaluating Condition Table\n");
1921 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1922 if (rc == ERROR_SUCCESS)
1924 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1925 package);
1926 msiobj_release(&view->hdr);
1929 TRACE("Enabling or Disabling Components\n");
1930 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1932 if (comp->Condition)
1934 if (MSI_EvaluateConditionW(package,
1935 comp->Condition) == MSICONDITION_FALSE)
1937 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1938 comp->Enabled = FALSE;
1943 MSI_SetPropertyW(package,szCosting,szOne);
1944 /* set default run level if not set */
1945 level = msi_dup_property( package, szlevel );
1946 if (!level)
1947 MSI_SetPropertyW(package,szlevel, szOne);
1948 msi_free(level);
1950 ACTION_UpdateInstallStates(package);
1952 return SetFeatureStates(package);
1955 /* OK this value is "interpreted" and then formatted based on the
1956 first few characters */
1957 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1958 DWORD *size)
1960 LPSTR data = NULL;
1961 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1963 if (value[1]=='x')
1965 LPWSTR ptr;
1966 CHAR byte[5];
1967 LPWSTR deformated = NULL;
1968 int count;
1970 deformat_string(package, &value[2], &deformated);
1972 /* binary value type */
1973 ptr = deformated;
1974 *type = REG_BINARY;
1975 if (strlenW(ptr)%2)
1976 *size = (strlenW(ptr)/2)+1;
1977 else
1978 *size = strlenW(ptr)/2;
1980 data = msi_alloc(*size);
1982 byte[0] = '0';
1983 byte[1] = 'x';
1984 byte[4] = 0;
1985 count = 0;
1986 /* if uneven pad with a zero in front */
1987 if (strlenW(ptr)%2)
1989 byte[2]= '0';
1990 byte[3]= *ptr;
1991 ptr++;
1992 data[count] = (BYTE)strtol(byte,NULL,0);
1993 count ++;
1994 TRACE("Uneven byte count\n");
1996 while (*ptr)
1998 byte[2]= *ptr;
1999 ptr++;
2000 byte[3]= *ptr;
2001 ptr++;
2002 data[count] = (BYTE)strtol(byte,NULL,0);
2003 count ++;
2005 msi_free(deformated);
2007 TRACE("Data %li bytes(%i)\n",*size,count);
2009 else
2011 LPWSTR deformated;
2012 LPWSTR p;
2013 DWORD d = 0;
2014 deformat_string(package, &value[1], &deformated);
2016 *type=REG_DWORD;
2017 *size = sizeof(DWORD);
2018 data = msi_alloc(*size);
2019 p = deformated;
2020 if (*p == '-')
2021 p++;
2022 while (*p)
2024 if ( (*p < '0') || (*p > '9') )
2025 break;
2026 d *= 10;
2027 d += (*p - '0');
2028 p++;
2030 if (deformated[0] == '-')
2031 d = -d;
2032 *(LPDWORD)data = d;
2033 TRACE("DWORD %li\n",*(LPDWORD)data);
2035 msi_free(deformated);
2038 else
2040 static const WCHAR szMulti[] = {'[','~',']',0};
2041 LPCWSTR ptr;
2042 *type=REG_SZ;
2044 if (value[0]=='#')
2046 if (value[1]=='%')
2048 ptr = &value[2];
2049 *type=REG_EXPAND_SZ;
2051 else
2052 ptr = &value[1];
2054 else
2055 ptr=value;
2057 if (strstrW(value,szMulti))
2058 *type = REG_MULTI_SZ;
2060 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2062 return data;
2065 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2067 MSIPACKAGE *package = (MSIPACKAGE*)param;
2068 static const WCHAR szHCR[] =
2069 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2070 'R','O','O','T','\\',0};
2071 static const WCHAR szHCU[] =
2072 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2073 'U','S','E','R','\\',0};
2074 static const WCHAR szHLM[] =
2075 {'H','K','E','Y','_','L','O','C','A','L','_',
2076 'M','A','C','H','I','N','E','\\',0};
2077 static const WCHAR szHU[] =
2078 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2080 LPSTR value_data = NULL;
2081 HKEY root_key, hkey;
2082 DWORD type,size;
2083 LPWSTR deformated;
2084 LPCWSTR szRoot, component, name, key, value;
2085 MSICOMPONENT *comp;
2086 MSIRECORD * uirow;
2087 LPWSTR uikey;
2088 INT root;
2089 BOOL check_first = FALSE;
2090 UINT rc;
2092 ui_progress(package,2,0,0,0);
2094 value = NULL;
2095 key = NULL;
2096 uikey = NULL;
2097 name = NULL;
2099 component = MSI_RecordGetString(row, 6);
2100 comp = get_loaded_component(package,component);
2101 if (!comp)
2102 return ERROR_SUCCESS;
2104 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2106 TRACE("Skipping write due to disabled component %s\n",
2107 debugstr_w(component));
2109 comp->Action = comp->Installed;
2111 return ERROR_SUCCESS;
2114 comp->Action = INSTALLSTATE_LOCAL;
2116 name = MSI_RecordGetString(row, 4);
2117 if( MSI_RecordIsNull(row,5) && name )
2119 /* null values can have special meanings */
2120 if (name[0]=='-' && name[1] == 0)
2121 return ERROR_SUCCESS;
2122 else if ((name[0]=='+' && name[1] == 0) ||
2123 (name[0] == '*' && name[1] == 0))
2124 name = NULL;
2125 check_first = TRUE;
2128 root = MSI_RecordGetInteger(row,2);
2129 key = MSI_RecordGetString(row, 3);
2131 /* get the root key */
2132 switch (root)
2134 case -1:
2136 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2137 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2138 if (all_users && all_users[0] == '1')
2140 root_key = HKEY_LOCAL_MACHINE;
2141 szRoot = szHLM;
2143 else
2145 root_key = HKEY_CURRENT_USER;
2146 szRoot = szHCU;
2148 msi_free(all_users);
2150 break;
2151 case 0: root_key = HKEY_CLASSES_ROOT;
2152 szRoot = szHCR;
2153 break;
2154 case 1: root_key = HKEY_CURRENT_USER;
2155 szRoot = szHCU;
2156 break;
2157 case 2: root_key = HKEY_LOCAL_MACHINE;
2158 szRoot = szHLM;
2159 break;
2160 case 3: root_key = HKEY_USERS;
2161 szRoot = szHU;
2162 break;
2163 default:
2164 ERR("Unknown root %i\n",root);
2165 root_key=NULL;
2166 szRoot = NULL;
2167 break;
2169 if (!root_key)
2170 return ERROR_SUCCESS;
2172 deformat_string(package, key , &deformated);
2173 size = strlenW(deformated) + strlenW(szRoot) + 1;
2174 uikey = msi_alloc(size*sizeof(WCHAR));
2175 strcpyW(uikey,szRoot);
2176 strcatW(uikey,deformated);
2178 if (RegCreateKeyW( root_key, deformated, &hkey))
2180 ERR("Could not create key %s\n",debugstr_w(deformated));
2181 msi_free(deformated);
2182 msi_free(uikey);
2183 return ERROR_SUCCESS;
2185 msi_free(deformated);
2187 value = MSI_RecordGetString(row,5);
2188 if (value)
2189 value_data = parse_value(package, value, &type, &size);
2190 else
2192 static const WCHAR szEmpty[] = {0};
2193 value_data = (LPSTR)strdupW(szEmpty);
2194 size = 0;
2195 type = REG_SZ;
2198 deformat_string(package, name, &deformated);
2200 /* get the double nulls to terminate SZ_MULTI */
2201 if (type == REG_MULTI_SZ)
2202 size +=sizeof(WCHAR);
2204 if (!check_first)
2206 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2207 debugstr_w(uikey));
2208 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2210 else
2212 DWORD sz = 0;
2213 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2214 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2216 TRACE("value %s of %s checked already exists\n",
2217 debugstr_w(deformated), debugstr_w(uikey));
2219 else
2221 TRACE("Checked and setting value %s of %s\n",
2222 debugstr_w(deformated), debugstr_w(uikey));
2223 if (deformated || size)
2224 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2227 RegCloseKey(hkey);
2229 uirow = MSI_CreateRecord(3);
2230 MSI_RecordSetStringW(uirow,2,deformated);
2231 MSI_RecordSetStringW(uirow,1,uikey);
2233 if (type == REG_SZ)
2234 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2235 else
2236 MSI_RecordSetStringW(uirow,3,value);
2238 ui_actiondata(package,szWriteRegistryValues,uirow);
2239 msiobj_release( &uirow->hdr );
2241 msi_free(value_data);
2242 msi_free(deformated);
2243 msi_free(uikey);
2245 return ERROR_SUCCESS;
2248 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2250 UINT rc;
2251 MSIQUERY * view;
2252 static const WCHAR ExecSeqQuery[] =
2253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2254 '`','R','e','g','i','s','t','r','y','`',0 };
2256 if (!package)
2257 return ERROR_INVALID_HANDLE;
2259 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2260 if (rc != ERROR_SUCCESS)
2261 return ERROR_SUCCESS;
2263 /* increment progress bar each time action data is sent */
2264 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2266 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2268 msiobj_release(&view->hdr);
2269 return rc;
2272 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2274 package->script->CurrentlyScripting = TRUE;
2276 return ERROR_SUCCESS;
2280 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2282 MSICOMPONENT *comp;
2283 DWORD progress = 0;
2284 DWORD total = 0;
2285 static const WCHAR q1[]=
2286 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2287 '`','R','e','g','i','s','t','r','y','`',0};
2288 UINT rc;
2289 MSIQUERY * view;
2290 MSIFEATURE *feature;
2291 MSIFILE *file;
2293 TRACE("InstallValidate\n");
2295 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2296 if (rc == ERROR_SUCCESS)
2298 MSI_IterateRecords( view, &progress, NULL, package );
2299 msiobj_release( &view->hdr );
2300 total += progress * REG_PROGRESS_VALUE;
2303 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2304 total += COMPONENT_PROGRESS_VALUE;
2306 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2307 total += file->FileSize;
2309 ui_progress(package,0,total,0,0);
2311 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2313 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2314 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2315 feature->ActionRequest);
2318 return ERROR_SUCCESS;
2321 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2323 MSIPACKAGE* package = (MSIPACKAGE*)param;
2324 LPCWSTR cond = NULL;
2325 LPCWSTR message = NULL;
2326 static const WCHAR title[]=
2327 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2329 cond = MSI_RecordGetString(row,1);
2331 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2333 LPWSTR deformated;
2334 message = MSI_RecordGetString(row,2);
2335 deformat_string(package,message,&deformated);
2336 MessageBoxW(NULL,deformated,title,MB_OK);
2337 msi_free(deformated);
2338 return ERROR_FUNCTION_FAILED;
2341 return ERROR_SUCCESS;
2344 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2346 UINT rc;
2347 MSIQUERY * view = NULL;
2348 static const WCHAR ExecSeqQuery[] =
2349 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2350 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2352 TRACE("Checking launch conditions\n");
2354 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2355 if (rc != ERROR_SUCCESS)
2356 return ERROR_SUCCESS;
2358 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2359 msiobj_release(&view->hdr);
2361 return rc;
2364 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2367 if (!cmp->KeyPath)
2368 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2370 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2372 MSIRECORD * row = 0;
2373 UINT root,len;
2374 LPWSTR deformated,buffer,deformated_name;
2375 LPCWSTR key,name;
2376 static const WCHAR ExecSeqQuery[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','R','e','g','i','s','t','r','y','`',' ',
2379 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2380 ' ','=',' ' ,'\'','%','s','\'',0 };
2381 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2382 static const WCHAR fmt2[]=
2383 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2385 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2386 if (!row)
2387 return NULL;
2389 root = MSI_RecordGetInteger(row,2);
2390 key = MSI_RecordGetString(row, 3);
2391 name = MSI_RecordGetString(row, 4);
2392 deformat_string(package, key , &deformated);
2393 deformat_string(package, name, &deformated_name);
2395 len = strlenW(deformated) + 6;
2396 if (deformated_name)
2397 len+=strlenW(deformated_name);
2399 buffer = msi_alloc( len *sizeof(WCHAR));
2401 if (deformated_name)
2402 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2403 else
2404 sprintfW(buffer,fmt,root,deformated);
2406 msi_free(deformated);
2407 msi_free(deformated_name);
2408 msiobj_release(&row->hdr);
2410 return buffer;
2412 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2414 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2415 return NULL;
2417 else
2419 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2421 if (file)
2422 return strdupW( file->TargetPath );
2424 return NULL;
2427 static HKEY openSharedDLLsKey(void)
2429 HKEY hkey=0;
2430 static const WCHAR path[] =
2431 {'S','o','f','t','w','a','r','e','\\',
2432 'M','i','c','r','o','s','o','f','t','\\',
2433 'W','i','n','d','o','w','s','\\',
2434 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2435 'S','h','a','r','e','d','D','L','L','s',0};
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2438 return hkey;
2441 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2443 HKEY hkey;
2444 DWORD count=0;
2445 DWORD type;
2446 DWORD sz = sizeof(count);
2447 DWORD rc;
2449 hkey = openSharedDLLsKey();
2450 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2451 if (rc != ERROR_SUCCESS)
2452 count = 0;
2453 RegCloseKey(hkey);
2454 return count;
2457 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2459 HKEY hkey;
2461 hkey = openSharedDLLsKey();
2462 if (count > 0)
2463 msi_reg_set_val_dword( hkey, path, count );
2464 else
2465 RegDeleteValueW(hkey,path);
2466 RegCloseKey(hkey);
2467 return count;
2471 * Return TRUE if the count should be written out and FALSE if not
2473 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2475 MSIFEATURE *feature;
2476 INT count = 0;
2477 BOOL write = FALSE;
2479 /* only refcount DLLs */
2480 if (comp->KeyPath == NULL ||
2481 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2482 comp->Attributes & msidbComponentAttributesODBCDataSource)
2483 write = FALSE;
2484 else
2486 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2487 write = (count > 0);
2489 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2490 write = TRUE;
2493 /* increment counts */
2494 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2496 ComponentList *cl;
2498 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2499 continue;
2501 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2503 if ( cl->component == comp )
2504 count++;
2508 /* decrement counts */
2509 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2511 ComponentList *cl;
2513 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2514 continue;
2516 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2518 if ( cl->component == comp )
2519 count--;
2523 /* ref count all the files in the component */
2524 if (write)
2526 MSIFILE *file;
2528 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2530 if (file->Component == comp)
2531 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2535 /* add a count for permenent */
2536 if (comp->Attributes & msidbComponentAttributesPermanent)
2537 count ++;
2539 comp->RefCount = count;
2541 if (write)
2542 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2546 * Ok further analysis makes me think that this work is
2547 * actually done in the PublishComponents and PublishFeatures
2548 * step, and not here. It appears like the keypath and all that is
2549 * resolved in this step, however actually written in the Publish steps.
2550 * But we will leave it here for now because it is unclear
2552 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2554 WCHAR squished_pc[GUID_SIZE];
2555 WCHAR squished_cc[GUID_SIZE];
2556 UINT rc;
2557 MSICOMPONENT *comp;
2558 HKEY hkey=0,hkey2=0;
2560 /* writes the Component and Features values to the registry */
2562 rc = MSIREG_OpenComponents(&hkey);
2563 if (rc != ERROR_SUCCESS)
2564 goto end;
2566 squash_guid(package->ProductCode,squished_pc);
2567 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2569 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2571 ui_progress(package,2,0,0,0);
2572 if (comp->ComponentId)
2574 MSIRECORD * uirow;
2576 squash_guid(comp->ComponentId,squished_cc);
2578 msi_free(comp->FullKeypath);
2579 comp->FullKeypath = resolve_keypath( package, comp );
2581 /* do the refcounting */
2582 ACTION_RefCountComponent( package, comp );
2584 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2585 debugstr_w(comp->Component),
2586 debugstr_w(squished_cc),
2587 debugstr_w(comp->FullKeypath),
2588 comp->RefCount);
2590 * Write the keypath out if the component is to be registered
2591 * and delete the key if the component is to be deregistered
2593 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2595 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2596 if (rc != ERROR_SUCCESS)
2597 continue;
2599 if (comp->FullKeypath)
2601 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2603 if (comp->Attributes & msidbComponentAttributesPermanent)
2605 static const WCHAR szPermKey[] =
2606 { '0','0','0','0','0','0','0','0','0','0','0','0',
2607 '0','0','0','0','0','0','0','0','0','0','0','0',
2608 '0','0','0','0','0','0','0','0',0};
2610 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2613 RegCloseKey(hkey2);
2615 /* UI stuff */
2616 uirow = MSI_CreateRecord(3);
2617 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2618 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2619 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2620 ui_actiondata(package,szProcessComponents,uirow);
2621 msiobj_release( &uirow->hdr );
2624 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2626 DWORD res;
2628 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2629 if (rc != ERROR_SUCCESS)
2630 continue;
2632 RegDeleteValueW(hkey2,squished_pc);
2634 /* if the key is empty delete it */
2635 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2636 RegCloseKey(hkey2);
2637 if (res == ERROR_NO_MORE_ITEMS)
2638 RegDeleteKeyW(hkey,squished_cc);
2640 /* UI stuff */
2641 uirow = MSI_CreateRecord(2);
2642 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2643 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2644 ui_actiondata(package,szProcessComponents,uirow);
2645 msiobj_release( &uirow->hdr );
2649 end:
2650 RegCloseKey(hkey);
2651 return rc;
2654 typedef struct {
2655 CLSID clsid;
2656 LPWSTR source;
2658 LPWSTR path;
2659 ITypeLib *ptLib;
2660 } typelib_struct;
2662 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2663 LPWSTR lpszName, LONG_PTR lParam)
2665 TLIBATTR *attr;
2666 typelib_struct *tl_struct = (typelib_struct*) lParam;
2667 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2668 int sz;
2669 HRESULT res;
2671 if (!IS_INTRESOURCE(lpszName))
2673 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2674 return TRUE;
2677 sz = strlenW(tl_struct->source)+4;
2678 sz *= sizeof(WCHAR);
2680 if ((INT)lpszName == 1)
2681 tl_struct->path = strdupW(tl_struct->source);
2682 else
2684 tl_struct->path = msi_alloc(sz);
2685 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2688 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2689 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2690 if (!SUCCEEDED(res))
2692 msi_free(tl_struct->path);
2693 tl_struct->path = NULL;
2695 return TRUE;
2698 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2699 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2701 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2702 return FALSE;
2705 msi_free(tl_struct->path);
2706 tl_struct->path = NULL;
2708 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2709 ITypeLib_Release(tl_struct->ptLib);
2711 return TRUE;
2714 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2716 MSIPACKAGE* package = (MSIPACKAGE*)param;
2717 LPCWSTR component;
2718 MSICOMPONENT *comp;
2719 MSIFILE *file;
2720 typelib_struct tl_struct;
2721 HMODULE module;
2722 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2724 component = MSI_RecordGetString(row,3);
2725 comp = get_loaded_component(package,component);
2726 if (!comp)
2727 return ERROR_SUCCESS;
2729 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2731 TRACE("Skipping typelib reg due to disabled component\n");
2733 comp->Action = comp->Installed;
2735 return ERROR_SUCCESS;
2738 comp->Action = INSTALLSTATE_LOCAL;
2740 file = get_loaded_file( package, comp->KeyPath );
2741 if (!file)
2742 return ERROR_SUCCESS;
2744 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2745 if (module)
2747 LPCWSTR guid;
2748 guid = MSI_RecordGetString(row,1);
2749 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2750 tl_struct.source = strdupW( file->TargetPath );
2751 tl_struct.path = NULL;
2753 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2754 (LONG_PTR)&tl_struct);
2756 if (tl_struct.path)
2758 LPWSTR help = NULL;
2759 LPCWSTR helpid;
2760 HRESULT res;
2762 helpid = MSI_RecordGetString(row,6);
2764 if (helpid)
2765 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2766 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2767 msi_free(help);
2769 if (!SUCCEEDED(res))
2770 ERR("Failed to register type library %s\n",
2771 debugstr_w(tl_struct.path));
2772 else
2774 ui_actiondata(package,szRegisterTypeLibraries,row);
2776 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2779 ITypeLib_Release(tl_struct.ptLib);
2780 msi_free(tl_struct.path);
2782 else
2783 ERR("Failed to load type library %s\n",
2784 debugstr_w(tl_struct.source));
2786 FreeLibrary(module);
2787 msi_free(tl_struct.source);
2789 else
2790 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2792 return ERROR_SUCCESS;
2795 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2798 * OK this is a bit confusing.. I am given a _Component key and I believe
2799 * that the file that is being registered as a type library is the "key file
2800 * of that component" which I interpret to mean "The file in the KeyPath of
2801 * that component".
2803 UINT rc;
2804 MSIQUERY * view;
2805 static const WCHAR Query[] =
2806 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2807 '`','T','y','p','e','L','i','b','`',0};
2809 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2810 if (rc != ERROR_SUCCESS)
2811 return ERROR_SUCCESS;
2813 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2814 msiobj_release(&view->hdr);
2815 return rc;
2818 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2820 MSIPACKAGE *package = (MSIPACKAGE*)param;
2821 LPWSTR target_file, target_folder;
2822 LPCWSTR buffer;
2823 WCHAR filename[0x100];
2824 DWORD sz;
2825 MSICOMPONENT *comp;
2826 static const WCHAR szlnk[]={'.','l','n','k',0};
2827 IShellLinkW *sl;
2828 IPersistFile *pf;
2829 HRESULT res;
2831 buffer = MSI_RecordGetString(row,4);
2832 comp = get_loaded_component(package,buffer);
2833 if (!comp)
2834 return ERROR_SUCCESS;
2836 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2838 TRACE("Skipping shortcut creation due to disabled component\n");
2840 comp->Action = comp->Installed;
2842 return ERROR_SUCCESS;
2845 comp->Action = INSTALLSTATE_LOCAL;
2847 ui_actiondata(package,szCreateShortcuts,row);
2849 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2850 &IID_IShellLinkW, (LPVOID *) &sl );
2852 if (FAILED(res))
2854 ERR("Is IID_IShellLink\n");
2855 return ERROR_SUCCESS;
2858 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2859 if( FAILED( res ) )
2861 ERR("Is IID_IPersistFile\n");
2862 return ERROR_SUCCESS;
2865 buffer = MSI_RecordGetString(row,2);
2866 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2868 /* may be needed because of a bug somehwere else */
2869 create_full_pathW(target_folder);
2871 sz = 0x100;
2872 MSI_RecordGetStringW(row,3,filename,&sz);
2873 reduce_to_longfilename(filename);
2874 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2875 strcatW(filename,szlnk);
2876 target_file = build_directory_name(2, target_folder, filename);
2877 msi_free(target_folder);
2879 buffer = MSI_RecordGetString(row,5);
2880 if (strchrW(buffer,'['))
2882 LPWSTR deformated;
2883 deformat_string(package,buffer,&deformated);
2884 IShellLinkW_SetPath(sl,deformated);
2885 msi_free(deformated);
2887 else
2889 FIXME("poorly handled shortcut format, advertised shortcut\n");
2890 IShellLinkW_SetPath(sl,comp->FullKeypath);
2893 if (!MSI_RecordIsNull(row,6))
2895 LPWSTR deformated;
2896 buffer = MSI_RecordGetString(row,6);
2897 deformat_string(package,buffer,&deformated);
2898 IShellLinkW_SetArguments(sl,deformated);
2899 msi_free(deformated);
2902 if (!MSI_RecordIsNull(row,7))
2904 buffer = MSI_RecordGetString(row,7);
2905 IShellLinkW_SetDescription(sl,buffer);
2908 if (!MSI_RecordIsNull(row,8))
2909 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2911 if (!MSI_RecordIsNull(row,9))
2913 LPWSTR Path;
2914 INT index;
2916 buffer = MSI_RecordGetString(row,9);
2918 Path = build_icon_path(package,buffer);
2919 index = MSI_RecordGetInteger(row,10);
2921 IShellLinkW_SetIconLocation(sl,Path,index);
2922 msi_free(Path);
2925 if (!MSI_RecordIsNull(row,11))
2926 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2928 if (!MSI_RecordIsNull(row,12))
2930 LPWSTR Path;
2931 buffer = MSI_RecordGetString(row,12);
2932 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2933 IShellLinkW_SetWorkingDirectory(sl,Path);
2934 msi_free(Path);
2937 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2938 IPersistFile_Save(pf,target_file,FALSE);
2940 msi_free(target_file);
2942 IPersistFile_Release( pf );
2943 IShellLinkW_Release( sl );
2945 return ERROR_SUCCESS;
2948 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2950 UINT rc;
2951 HRESULT res;
2952 MSIQUERY * view;
2953 static const WCHAR Query[] =
2954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2955 '`','S','h','o','r','t','c','u','t','`',0};
2957 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2958 if (rc != ERROR_SUCCESS)
2959 return ERROR_SUCCESS;
2961 res = CoInitialize( NULL );
2962 if (FAILED (res))
2964 ERR("CoInitialize failed\n");
2965 return ERROR_FUNCTION_FAILED;
2968 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2969 msiobj_release(&view->hdr);
2971 CoUninitialize();
2973 return rc;
2976 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2978 MSIPACKAGE* package = (MSIPACKAGE*)param;
2979 HANDLE the_file;
2980 LPWSTR FilePath;
2981 LPCWSTR FileName;
2982 CHAR buffer[1024];
2983 DWORD sz;
2984 UINT rc;
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);
3025 return ERROR_SUCCESS;
3029 * 99% of the work done here is only done for
3030 * advertised installs. However this is where the
3031 * Icon table is processed and written out
3032 * so that is what I am going to do here.
3034 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3036 UINT rc;
3037 MSIQUERY * view;
3038 static const WCHAR Query[]=
3039 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3040 '`','I','c','o','n','`',0};
3041 /* for registry stuff */
3042 HKEY hkey=0;
3043 HKEY hukey=0;
3044 static const WCHAR szProductLanguage[] =
3045 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3046 static const WCHAR szARPProductIcon[] =
3047 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3048 static const WCHAR szProductVersion[] =
3049 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3050 DWORD langid;
3051 LPWSTR buffer;
3052 DWORD size;
3053 MSIHANDLE hDb, hSumInfo;
3055 /* write out icon files */
3057 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3058 if (rc == ERROR_SUCCESS)
3060 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3061 msiobj_release(&view->hdr);
3064 /* ok there is a lot more done here but i need to figure out what */
3066 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3067 if (rc != ERROR_SUCCESS)
3068 goto end;
3070 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3071 if (rc != ERROR_SUCCESS)
3072 goto end;
3075 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3076 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3077 msi_free(buffer);
3079 langid = msi_get_property_int( package, szProductLanguage, 0 );
3080 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3082 buffer = msi_dup_property( package, szARPProductIcon );
3083 if (buffer)
3085 LPWSTR path = build_icon_path(package,buffer);
3086 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3087 msi_free( path );
3089 msi_free(buffer);
3091 buffer = msi_dup_property( package, szProductVersion );
3092 if (buffer)
3094 DWORD verdword = build_version_dword(buffer);
3095 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3097 msi_free(buffer);
3099 /* FIXME: Need to write more keys to the user registry */
3101 hDb= alloc_msihandle( &package->db->hdr );
3102 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3103 MsiCloseHandle(hDb);
3104 if (rc == ERROR_SUCCESS)
3106 WCHAR guidbuffer[0x200];
3107 size = 0x200;
3108 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3109 guidbuffer, &size);
3110 if (rc == ERROR_SUCCESS)
3112 WCHAR squashed[GUID_SIZE];
3113 /* for now we only care about the first guid */
3114 LPWSTR ptr = strchrW(guidbuffer,';');
3115 if (ptr) *ptr = 0;
3116 squash_guid(guidbuffer,squashed);
3117 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3119 else
3121 ERR("Unable to query Revision_Number...\n");
3122 rc = ERROR_SUCCESS;
3124 MsiCloseHandle(hSumInfo);
3126 else
3128 ERR("Unable to open Summary Information\n");
3129 rc = ERROR_SUCCESS;
3132 end:
3134 RegCloseKey(hkey);
3135 RegCloseKey(hukey);
3137 return rc;
3140 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3142 MSIPACKAGE *package = (MSIPACKAGE*)param;
3143 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3144 LPWSTR deformated_section, deformated_key, deformated_value;
3145 LPWSTR folder, fullname = NULL;
3146 MSIRECORD * uirow;
3147 INT action;
3148 MSICOMPONENT *comp;
3149 static const WCHAR szWindowsFolder[] =
3150 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3152 component = MSI_RecordGetString(row, 8);
3153 comp = get_loaded_component(package,component);
3155 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3157 TRACE("Skipping ini file due to disabled component %s\n",
3158 debugstr_w(component));
3160 comp->Action = comp->Installed;
3162 return ERROR_SUCCESS;
3165 comp->Action = INSTALLSTATE_LOCAL;
3167 identifier = MSI_RecordGetString(row,1);
3168 filename = MSI_RecordGetString(row,2);
3169 dirproperty = MSI_RecordGetString(row,3);
3170 section = MSI_RecordGetString(row,4);
3171 key = MSI_RecordGetString(row,5);
3172 value = MSI_RecordGetString(row,6);
3173 action = MSI_RecordGetInteger(row,7);
3175 deformat_string(package,section,&deformated_section);
3176 deformat_string(package,key,&deformated_key);
3177 deformat_string(package,value,&deformated_value);
3179 if (dirproperty)
3181 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3182 if (!folder)
3183 folder = msi_dup_property( package, dirproperty );
3185 else
3186 folder = msi_dup_property( package, szWindowsFolder );
3188 if (!folder)
3190 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3191 goto cleanup;
3194 fullname = build_directory_name(2, folder, filename);
3196 if (action == 0)
3198 TRACE("Adding value %s to section %s in %s\n",
3199 debugstr_w(deformated_key), debugstr_w(deformated_section),
3200 debugstr_w(fullname));
3201 WritePrivateProfileStringW(deformated_section, deformated_key,
3202 deformated_value, fullname);
3204 else if (action == 1)
3206 WCHAR returned[10];
3207 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3208 returned, 10, fullname);
3209 if (returned[0] == 0)
3211 TRACE("Adding value %s to section %s in %s\n",
3212 debugstr_w(deformated_key), debugstr_w(deformated_section),
3213 debugstr_w(fullname));
3215 WritePrivateProfileStringW(deformated_section, deformated_key,
3216 deformated_value, fullname);
3219 else if (action == 3)
3220 FIXME("Append to existing section not yet implemented\n");
3222 uirow = MSI_CreateRecord(4);
3223 MSI_RecordSetStringW(uirow,1,identifier);
3224 MSI_RecordSetStringW(uirow,2,deformated_section);
3225 MSI_RecordSetStringW(uirow,3,deformated_key);
3226 MSI_RecordSetStringW(uirow,4,deformated_value);
3227 ui_actiondata(package,szWriteIniValues,uirow);
3228 msiobj_release( &uirow->hdr );
3229 cleanup:
3230 msi_free(fullname);
3231 msi_free(folder);
3232 msi_free(deformated_key);
3233 msi_free(deformated_value);
3234 msi_free(deformated_section);
3235 return ERROR_SUCCESS;
3238 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3240 UINT rc;
3241 MSIQUERY * view;
3242 static const WCHAR ExecSeqQuery[] =
3243 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3244 '`','I','n','i','F','i','l','e','`',0};
3246 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3247 if (rc != ERROR_SUCCESS)
3249 TRACE("no IniFile table\n");
3250 return ERROR_SUCCESS;
3253 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3254 msiobj_release(&view->hdr);
3255 return rc;
3258 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3260 MSIPACKAGE *package = (MSIPACKAGE*)param;
3261 LPCWSTR filename;
3262 LPWSTR FullName;
3263 MSIFILE *file;
3264 DWORD len;
3265 static const WCHAR ExeStr[] =
3266 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3267 static const WCHAR close[] = {'\"',0};
3268 STARTUPINFOW si;
3269 PROCESS_INFORMATION info;
3270 BOOL brc;
3272 memset(&si,0,sizeof(STARTUPINFOW));
3274 filename = MSI_RecordGetString(row,1);
3275 file = get_loaded_file( package, filename );
3277 if (!file)
3279 ERR("Unable to find file id %s\n",debugstr_w(filename));
3280 return ERROR_SUCCESS;
3283 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3285 FullName = msi_alloc(len*sizeof(WCHAR));
3286 strcpyW(FullName,ExeStr);
3287 strcatW( FullName, file->TargetPath );
3288 strcatW(FullName,close);
3290 TRACE("Registering %s\n",debugstr_w(FullName));
3291 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3292 &si, &info);
3294 if (brc)
3295 msi_dialog_check_messages(info.hProcess);
3297 msi_free(FullName);
3298 return ERROR_SUCCESS;
3301 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3303 UINT rc;
3304 MSIQUERY * view;
3305 static const WCHAR ExecSeqQuery[] =
3306 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3307 '`','S','e','l','f','R','e','g','`',0};
3309 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3310 if (rc != ERROR_SUCCESS)
3312 TRACE("no SelfReg table\n");
3313 return ERROR_SUCCESS;
3316 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3317 msiobj_release(&view->hdr);
3319 return ERROR_SUCCESS;
3322 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3324 MSIFEATURE *feature;
3325 UINT rc;
3326 HKEY hkey=0;
3327 HKEY hukey=0;
3329 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3330 if (rc != ERROR_SUCCESS)
3331 goto end;
3333 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3334 if (rc != ERROR_SUCCESS)
3335 goto end;
3337 /* here the guids are base 85 encoded */
3338 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3340 ComponentList *cl;
3341 LPWSTR data = NULL;
3342 GUID clsid;
3343 INT size;
3344 BOOL absent = FALSE;
3346 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3347 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3348 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3349 absent = TRUE;
3351 size = 1;
3352 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3354 size += 21;
3356 if (feature->Feature_Parent)
3357 size += strlenW( feature->Feature_Parent )+2;
3359 data = msi_alloc(size * sizeof(WCHAR));
3361 data[0] = 0;
3362 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3364 MSICOMPONENT* component = cl->component;
3365 WCHAR buf[21];
3367 memset(buf,0,sizeof(buf));
3368 if (component->ComponentId)
3370 TRACE("From %s\n",debugstr_w(component->ComponentId));
3371 CLSIDFromString(component->ComponentId, &clsid);
3372 encode_base85_guid(&clsid,buf);
3373 TRACE("to %s\n",debugstr_w(buf));
3374 strcatW(data,buf);
3377 if (feature->Feature_Parent)
3379 static const WCHAR sep[] = {'\2',0};
3380 strcatW(data,sep);
3381 strcatW(data,feature->Feature_Parent);
3384 msi_reg_set_val_str( hkey, feature->Feature, data );
3385 msi_free(data);
3387 size = 0;
3388 if (feature->Feature_Parent)
3389 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3390 if (!absent)
3392 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3393 (LPBYTE)feature->Feature_Parent,size);
3395 else
3397 size += 2*sizeof(WCHAR);
3398 data = msi_alloc(size);
3399 data[0] = 0x6;
3400 data[1] = 0;
3401 if (feature->Feature_Parent)
3402 strcpyW( &data[1], feature->Feature_Parent );
3403 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3404 (LPBYTE)data,size);
3405 msi_free(data);
3409 end:
3410 RegCloseKey(hkey);
3411 RegCloseKey(hukey);
3412 return rc;
3415 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3417 static const WCHAR installerPathFmt[] = {
3418 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3419 static const WCHAR fmt[] = {
3420 '%','s','\\',
3421 'I','n','s','t','a','l','l','e','r','\\',
3422 '%','x','.','m','s','i',0};
3423 static const WCHAR szOriginalDatabase[] =
3424 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3425 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3426 INT num, start;
3427 LPWSTR msiFilePath;
3428 BOOL r;
3430 /* copy the package locally */
3431 num = GetTickCount() & 0xffff;
3432 if (!num)
3433 num = 1;
3434 start = num;
3435 GetWindowsDirectoryW( windir, MAX_PATH );
3436 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3439 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3440 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3441 if (handle != INVALID_HANDLE_VALUE)
3443 CloseHandle(handle);
3444 break;
3446 if (GetLastError() != ERROR_FILE_EXISTS &&
3447 GetLastError() != ERROR_SHARING_VIOLATION)
3448 break;
3449 if (!(++num & 0xffff)) num = 1;
3450 sprintfW(packagefile,fmt,num);
3451 } while (num != start);
3453 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3454 create_full_pathW(path);
3456 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3458 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3459 r = CopyFileW( msiFilePath, packagefile, FALSE);
3460 msi_free( msiFilePath );
3462 if (!r)
3464 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3465 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3466 return ERROR_FUNCTION_FAILED;
3469 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3470 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3471 return ERROR_SUCCESS;
3474 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3476 LPWSTR prop, val, key;
3477 static const LPCSTR propval[] = {
3478 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3479 "ARPCONTACT", "Contact",
3480 "ARPCOMMENTS", "Comments",
3481 "ProductName", "DisplayName",
3482 "ProductVersion", "DisplayVersion",
3483 "ARPHELPLINK", "HelpLink",
3484 "ARPHELPTELEPHONE", "HelpTelephone",
3485 "ARPINSTALLLOCATION", "InstallLocation",
3486 "SourceDir", "InstallSource",
3487 "Manufacturer", "Publisher",
3488 "ARPREADME", "Readme",
3489 "ARPSIZE", "Size",
3490 "ARPURLINFOABOUT", "URLInfoAbout",
3491 "ARPURLUPDATEINFO", "URLUpdateInfo",
3492 NULL,
3494 const LPCSTR *p = propval;
3496 while( *p )
3498 prop = strdupAtoW( *p++ );
3499 key = strdupAtoW( *p++ );
3500 val = msi_dup_property( package, prop );
3501 msi_reg_set_val_str( hkey, key, val );
3502 msi_free(val);
3503 msi_free(key);
3504 msi_free(prop);
3506 return ERROR_SUCCESS;
3509 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3511 HKEY hkey=0;
3512 LPWSTR buffer = NULL;
3513 UINT rc;
3514 DWORD size, langid;
3515 static const WCHAR szWindowsInstaller[] =
3516 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3517 static const WCHAR szUpgradeCode[] =
3518 {'U','p','g','r','a','d','e','C','o','d','e',0};
3519 static const WCHAR modpath_fmt[] =
3520 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3521 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3522 static const WCHAR szModifyPath[] =
3523 {'M','o','d','i','f','y','P','a','t','h',0};
3524 static const WCHAR szUninstallString[] =
3525 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3526 static const WCHAR szEstimatedSize[] =
3527 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3528 static const WCHAR szProductLanguage[] =
3529 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3530 static const WCHAR szProductVersion[] =
3531 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3533 SYSTEMTIME systime;
3534 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3535 LPWSTR upgrade_code;
3536 WCHAR szDate[9];
3538 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3539 if (rc != ERROR_SUCCESS)
3540 return rc;
3542 /* dump all the info i can grab */
3543 /* FIXME: Flesh out more information */
3545 msi_write_uninstall_property_vals( package, hkey );
3547 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3549 msi_make_package_local( package, hkey );
3551 /* do ModifyPath and UninstallString */
3552 size = deformat_string(package,modpath_fmt,&buffer);
3553 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3554 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3555 msi_free(buffer);
3557 /* FIXME: Write real Estimated Size when we have it */
3558 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3560 GetLocalTime(&systime);
3561 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3562 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3564 langid = msi_get_property_int( package, szProductLanguage, 0 );
3565 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3567 buffer = msi_dup_property( package, szProductVersion );
3568 if (buffer)
3570 DWORD verdword = build_version_dword(buffer);
3572 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3573 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3574 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3576 msi_free(buffer);
3578 /* Handle Upgrade Codes */
3579 upgrade_code = msi_dup_property( package, szUpgradeCode );
3580 if (upgrade_code)
3582 HKEY hkey2;
3583 WCHAR squashed[33];
3584 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3585 squash_guid(package->ProductCode,squashed);
3586 msi_reg_set_val_str( hkey2, squashed, NULL );
3587 RegCloseKey(hkey2);
3588 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3589 squash_guid(package->ProductCode,squashed);
3590 msi_reg_set_val_str( hkey2, squashed, NULL );
3591 RegCloseKey(hkey2);
3593 msi_free(upgrade_code);
3596 RegCloseKey(hkey);
3598 return ERROR_SUCCESS;
3601 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3603 return execute_script(package,INSTALL_SCRIPT);
3606 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3608 UINT rc;
3610 /* turn off scheduleing */
3611 package->script->CurrentlyScripting= FALSE;
3613 /* first do the same as an InstallExecute */
3614 rc = ACTION_InstallExecute(package);
3615 if (rc != ERROR_SUCCESS)
3616 return rc;
3618 /* then handle Commit Actions */
3619 rc = execute_script(package,COMMIT_SCRIPT);
3621 return rc;
3624 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3626 static const WCHAR RunOnce[] = {
3627 'S','o','f','t','w','a','r','e','\\',
3628 'M','i','c','r','o','s','o','f','t','\\',
3629 'W','i','n','d','o','w','s','\\',
3630 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3631 'R','u','n','O','n','c','e',0};
3632 static const WCHAR InstallRunOnce[] = {
3633 'S','o','f','t','w','a','r','e','\\',
3634 'M','i','c','r','o','s','o','f','t','\\',
3635 'W','i','n','d','o','w','s','\\',
3636 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3637 'I','n','s','t','a','l','l','e','r','\\',
3638 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3640 static const WCHAR msiexec_fmt[] = {
3641 '%','s',
3642 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3643 '\"','%','s','\"',0};
3644 static const WCHAR install_fmt[] = {
3645 '/','I',' ','\"','%','s','\"',' ',
3646 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3647 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3648 WCHAR buffer[256], sysdir[MAX_PATH];
3649 HKEY hkey;
3650 WCHAR squished_pc[100];
3652 squash_guid(package->ProductCode,squished_pc);
3654 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3655 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3656 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3657 squished_pc);
3659 msi_reg_set_val_str( hkey, squished_pc, buffer );
3660 RegCloseKey(hkey);
3662 TRACE("Reboot command %s\n",debugstr_w(buffer));
3664 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3665 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3667 msi_reg_set_val_str( hkey, squished_pc, buffer );
3668 RegCloseKey(hkey);
3670 return ERROR_INSTALL_SUSPEND;
3673 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3675 DWORD attrib;
3676 UINT rc;
3678 * we are currently doing what should be done here in the top level Install
3679 * however for Adminastrative and uninstalls this step will be needed
3681 if (!package->PackagePath)
3682 return ERROR_SUCCESS;
3684 attrib = GetFileAttributesW(package->PackagePath);
3685 if (attrib == INVALID_FILE_ATTRIBUTES)
3687 LPWSTR prompt;
3688 LPWSTR msg;
3689 DWORD size = 0;
3691 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3692 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3693 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3694 if (rc == ERROR_MORE_DATA)
3696 prompt = msi_alloc(size * sizeof(WCHAR));
3697 MsiSourceListGetInfoW(package->ProductCode, NULL,
3698 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3699 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3701 else
3702 prompt = strdupW(package->PackagePath);
3704 msg = generate_error_string(package,1302,1,prompt);
3705 while(attrib == INVALID_FILE_ATTRIBUTES)
3707 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3708 if (rc == IDCANCEL)
3710 rc = ERROR_INSTALL_USEREXIT;
3711 break;
3713 attrib = GetFileAttributesW(package->PackagePath);
3715 msi_free(prompt);
3716 rc = ERROR_SUCCESS;
3718 else
3719 return ERROR_SUCCESS;
3721 return rc;
3724 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3726 HKEY hkey=0;
3727 LPWSTR buffer;
3728 LPWSTR productid;
3729 UINT rc,i;
3731 static const WCHAR szPropKeys[][80] =
3733 {'P','r','o','d','u','c','t','I','D',0},
3734 {'U','S','E','R','N','A','M','E',0},
3735 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3736 {0},
3739 static const WCHAR szRegKeys[][80] =
3741 {'P','r','o','d','u','c','t','I','D',0},
3742 {'R','e','g','O','w','n','e','r',0},
3743 {'R','e','g','C','o','m','p','a','n','y',0},
3744 {0},
3747 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3748 if (!productid)
3749 return ERROR_SUCCESS;
3751 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3752 if (rc != ERROR_SUCCESS)
3753 goto end;
3755 for( i = 0; szPropKeys[i][0]; i++ )
3757 buffer = msi_dup_property( package, szPropKeys[i] );
3758 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3759 msi_free( buffer );
3762 end:
3763 msi_free(productid);
3764 RegCloseKey(hkey);
3766 return ERROR_SUCCESS;
3770 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3772 UINT rc;
3774 package->script->InWhatSequence |= SEQUENCE_EXEC;
3775 rc = ACTION_ProcessExecSequence(package,FALSE);
3776 return rc;
3781 * Code based off of code located here
3782 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3784 * Using string index 4 (full font name) instead of 1 (family name)
3786 static LPWSTR load_ttfname_from(LPCWSTR filename)
3788 HANDLE handle;
3789 LPWSTR ret = NULL;
3790 int i;
3792 typedef struct _tagTT_OFFSET_TABLE{
3793 USHORT uMajorVersion;
3794 USHORT uMinorVersion;
3795 USHORT uNumOfTables;
3796 USHORT uSearchRange;
3797 USHORT uEntrySelector;
3798 USHORT uRangeShift;
3799 }TT_OFFSET_TABLE;
3801 typedef struct _tagTT_TABLE_DIRECTORY{
3802 char szTag[4]; /* table name */
3803 ULONG uCheckSum; /* Check sum */
3804 ULONG uOffset; /* Offset from beginning of file */
3805 ULONG uLength; /* length of the table in bytes */
3806 }TT_TABLE_DIRECTORY;
3808 typedef struct _tagTT_NAME_TABLE_HEADER{
3809 USHORT uFSelector; /* format selector. Always 0 */
3810 USHORT uNRCount; /* Name Records count */
3811 USHORT uStorageOffset; /* Offset for strings storage,
3812 * from start of the table */
3813 }TT_NAME_TABLE_HEADER;
3815 typedef struct _tagTT_NAME_RECORD{
3816 USHORT uPlatformID;
3817 USHORT uEncodingID;
3818 USHORT uLanguageID;
3819 USHORT uNameID;
3820 USHORT uStringLength;
3821 USHORT uStringOffset; /* from start of storage area */
3822 }TT_NAME_RECORD;
3824 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3825 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3827 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3828 FILE_ATTRIBUTE_NORMAL, 0 );
3829 if (handle != INVALID_HANDLE_VALUE)
3831 TT_TABLE_DIRECTORY tblDir;
3832 BOOL bFound = FALSE;
3833 TT_OFFSET_TABLE ttOffsetTable;
3834 DWORD dwRead;
3836 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3837 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3838 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3839 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3841 if (ttOffsetTable.uMajorVersion != 1 ||
3842 ttOffsetTable.uMinorVersion != 0)
3843 return NULL;
3845 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3847 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3848 if (strncmp(tblDir.szTag,"name",4)==0)
3850 bFound = TRUE;
3851 tblDir.uLength = SWAPLONG(tblDir.uLength);
3852 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3853 break;
3857 if (bFound)
3859 TT_NAME_TABLE_HEADER ttNTHeader;
3860 TT_NAME_RECORD ttRecord;
3862 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3863 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3864 &dwRead,NULL);
3866 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3867 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3868 bFound = FALSE;
3869 for(i=0; i<ttNTHeader.uNRCount; i++)
3871 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3872 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3873 /* 4 is the Full Font Name */
3874 if(ttRecord.uNameID == 4)
3876 int nPos;
3877 LPSTR buf;
3878 static LPCSTR tt = " (TrueType)";
3880 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3881 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3882 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3883 SetFilePointer(handle, tblDir.uOffset +
3884 ttRecord.uStringOffset +
3885 ttNTHeader.uStorageOffset,
3886 NULL, FILE_BEGIN);
3887 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3888 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3889 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3890 if (strlen(buf) > 0)
3892 strcat(buf,tt);
3893 ret = strdupAtoW(buf);
3894 msi_free(buf);
3895 break;
3898 msi_free(buf);
3899 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3903 CloseHandle(handle);
3905 else
3906 ERR("Unable to open font file %s\n", debugstr_w(filename));
3908 TRACE("Returning fontname %s\n",debugstr_w(ret));
3909 return ret;
3912 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3914 MSIPACKAGE *package = (MSIPACKAGE*)param;
3915 LPWSTR name;
3916 LPCWSTR filename;
3917 MSIFILE *file;
3918 static const WCHAR regfont1[] =
3919 {'S','o','f','t','w','a','r','e','\\',
3920 'M','i','c','r','o','s','o','f','t','\\',
3921 'W','i','n','d','o','w','s',' ','N','T','\\',
3922 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3923 'F','o','n','t','s',0};
3924 static const WCHAR regfont2[] =
3925 {'S','o','f','t','w','a','r','e','\\',
3926 'M','i','c','r','o','s','o','f','t','\\',
3927 'W','i','n','d','o','w','s','\\',
3928 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3929 'F','o','n','t','s',0};
3930 HKEY hkey1;
3931 HKEY hkey2;
3933 filename = MSI_RecordGetString( row, 1 );
3934 file = get_loaded_file( package, filename );
3935 if (!file)
3937 ERR("Unable to load file\n");
3938 return ERROR_SUCCESS;
3941 /* check to make sure that component is installed */
3942 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3944 TRACE("Skipping: Component not scheduled for install\n");
3945 return ERROR_SUCCESS;
3948 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3949 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3951 if (MSI_RecordIsNull(row,2))
3952 name = load_ttfname_from( file->TargetPath );
3953 else
3954 name = msi_dup_record_field(row,2);
3956 if (name)
3958 msi_reg_set_val_str( hkey1, name, file->FileName );
3959 msi_reg_set_val_str( hkey2, name, file->FileName );
3962 msi_free(name);
3963 RegCloseKey(hkey1);
3964 RegCloseKey(hkey2);
3965 return ERROR_SUCCESS;
3968 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
3970 UINT rc;
3971 MSIQUERY * view;
3972 static const WCHAR ExecSeqQuery[] =
3973 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3974 '`','F','o','n','t','`',0};
3976 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3977 if (rc != ERROR_SUCCESS)
3979 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
3980 return ERROR_SUCCESS;
3983 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
3984 msiobj_release(&view->hdr);
3986 return ERROR_SUCCESS;
3989 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3991 MSIPACKAGE *package = (MSIPACKAGE*)param;
3992 LPCWSTR compgroupid=NULL;
3993 LPCWSTR feature=NULL;
3994 LPCWSTR text = NULL;
3995 LPCWSTR qualifier = NULL;
3996 LPCWSTR component = NULL;
3997 LPWSTR advertise = NULL;
3998 LPWSTR output = NULL;
3999 HKEY hkey;
4000 UINT rc = ERROR_SUCCESS;
4001 MSICOMPONENT *comp;
4002 DWORD sz = 0;
4004 component = MSI_RecordGetString(rec,3);
4005 comp = get_loaded_component(package,component);
4007 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4008 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4009 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4011 TRACE("Skipping: Component %s not scheduled for install\n",
4012 debugstr_w(component));
4014 return ERROR_SUCCESS;
4017 compgroupid = MSI_RecordGetString(rec,1);
4019 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4020 if (rc != ERROR_SUCCESS)
4021 goto end;
4023 text = MSI_RecordGetString(rec,4);
4024 qualifier = MSI_RecordGetString(rec,2);
4025 feature = MSI_RecordGetString(rec,5);
4027 advertise = create_component_advertise_string(package, comp, feature);
4029 sz = strlenW(advertise);
4031 if (text)
4032 sz += lstrlenW(text);
4034 sz+=3;
4035 sz *= sizeof(WCHAR);
4037 output = msi_alloc(sz);
4038 memset(output,0,sz);
4039 strcpyW(output,advertise);
4040 msi_free(advertise);
4042 if (text)
4043 strcatW(output,text);
4045 msi_reg_set_val_multi_str( hkey, qualifier, output );
4047 end:
4048 RegCloseKey(hkey);
4049 msi_free(output);
4051 return rc;
4055 * At present I am ignorning the advertised components part of this and only
4056 * focusing on the qualified component sets
4058 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4060 UINT rc;
4061 MSIQUERY * view;
4062 static const WCHAR ExecSeqQuery[] =
4063 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4064 '`','P','u','b','l','i','s','h',
4065 'C','o','m','p','o','n','e','n','t','`',0};
4067 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4068 if (rc != ERROR_SUCCESS)
4069 return ERROR_SUCCESS;
4071 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4072 msiobj_release(&view->hdr);
4074 return rc;
4077 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4078 LPCSTR action, LPCWSTR table )
4080 static const WCHAR query[] = {
4081 'S','E','L','E','C','T',' ','*',' ',
4082 'F','R','O','M',' ','`','%','s','`',0 };
4083 MSIQUERY *view = NULL;
4084 DWORD count = 0;
4085 UINT r;
4087 r = MSI_OpenQuery( package->db, &view, query, table );
4088 if (r == ERROR_SUCCESS)
4090 r = MSI_IterateRecords(view, &count, NULL, package);
4091 msiobj_release(&view->hdr);
4094 if (count)
4095 FIXME("%s -> %lu ignored %s table values\n",
4096 action, count, debugstr_w(table));
4098 return ERROR_SUCCESS;
4101 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4103 TRACE("%p\n", package);
4104 return ERROR_SUCCESS;
4107 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4109 static const WCHAR table[] =
4110 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4111 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4114 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4116 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4117 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4120 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4122 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4123 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4126 static UINT ACTION_BindImage( MSIPACKAGE *package )
4128 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4129 return msi_unimplemented_action_stub( package, "BindImage", table );
4132 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4134 static const WCHAR table[] = {
4135 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4136 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4139 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4141 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4142 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4145 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4147 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4148 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4151 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4153 static const WCHAR table[] = {
4154 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4155 return msi_unimplemented_action_stub( package, "InstallServices", table );
4158 static UINT ACTION_StartServices( MSIPACKAGE *package )
4160 static const WCHAR table[] = {
4161 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4162 return msi_unimplemented_action_stub( package, "StartServices", table );
4165 static UINT ACTION_StopServices( MSIPACKAGE *package )
4167 static const WCHAR table[] = {
4168 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4169 return msi_unimplemented_action_stub( package, "StopServices", table );
4172 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4174 static const WCHAR table[] = {
4175 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4176 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4179 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4181 static const WCHAR table[] = {
4182 'E','n','v','i','r','o','n','m','e','n','t',0 };
4183 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4186 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4188 static const WCHAR table[] = {
4189 'E','n','v','i','r','o','n','m','e','n','t',0 };
4190 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4193 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4195 static const WCHAR table[] = {
4196 'M','s','i','A','s','s','e','m','b','l','y',0 };
4197 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4200 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4202 static const WCHAR table[] = {
4203 'M','s','i','A','s','s','e','m','b','l','y',0 };
4204 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4207 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4209 static const WCHAR table[] = { 'F','o','n','t',0 };
4210 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4213 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4215 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4216 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4219 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4221 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4222 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4225 static struct _actions StandardActions[] = {
4226 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4227 { szAppSearch, ACTION_AppSearch },
4228 { szBindImage, ACTION_BindImage },
4229 { szCCPSearch, ACTION_CCPSearch},
4230 { szCostFinalize, ACTION_CostFinalize },
4231 { szCostInitialize, ACTION_CostInitialize },
4232 { szCreateFolders, ACTION_CreateFolders },
4233 { szCreateShortcuts, ACTION_CreateShortcuts },
4234 { szDeleteServices, ACTION_DeleteServices },
4235 { szDisableRollback, NULL},
4236 { szDuplicateFiles, ACTION_DuplicateFiles },
4237 { szExecuteAction, ACTION_ExecuteAction },
4238 { szFileCost, ACTION_FileCost },
4239 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4240 { szForceReboot, ACTION_ForceReboot },
4241 { szInstallAdminPackage, NULL},
4242 { szInstallExecute, ACTION_InstallExecute },
4243 { szInstallExecuteAgain, ACTION_InstallExecute },
4244 { szInstallFiles, ACTION_InstallFiles},
4245 { szInstallFinalize, ACTION_InstallFinalize },
4246 { szInstallInitialize, ACTION_InstallInitialize },
4247 { szInstallSFPCatalogFile, NULL},
4248 { szInstallValidate, ACTION_InstallValidate },
4249 { szIsolateComponents, ACTION_IsolateComponents },
4250 { szLaunchConditions, ACTION_LaunchConditions },
4251 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4252 { szMoveFiles, ACTION_MoveFiles },
4253 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4254 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4255 { szInstallODBC, NULL},
4256 { szInstallServices, ACTION_InstallServices },
4257 { szPatchFiles, ACTION_PatchFiles },
4258 { szProcessComponents, ACTION_ProcessComponents },
4259 { szPublishComponents, ACTION_PublishComponents },
4260 { szPublishFeatures, ACTION_PublishFeatures },
4261 { szPublishProduct, ACTION_PublishProduct },
4262 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4263 { szRegisterComPlus, NULL},
4264 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4265 { szRegisterFonts, ACTION_RegisterFonts },
4266 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4267 { szRegisterProduct, ACTION_RegisterProduct },
4268 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4269 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4270 { szRegisterUser, ACTION_RegisterUser},
4271 { szRemoveDuplicateFiles, NULL},
4272 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4273 { szRemoveExistingProducts, NULL},
4274 { szRemoveFiles, ACTION_RemoveFiles},
4275 { szRemoveFolders, NULL},
4276 { szRemoveIniValues, ACTION_RemoveIniValues },
4277 { szRemoveODBC, NULL},
4278 { szRemoveRegistryValues, NULL},
4279 { szRemoveShortcuts, NULL},
4280 { szResolveSource, ACTION_ResolveSource},
4281 { szRMCCPSearch, ACTION_RMCCPSearch},
4282 { szScheduleReboot, NULL},
4283 { szSelfRegModules, ACTION_SelfRegModules },
4284 { szSelfUnregModules, ACTION_SelfUnregModules },
4285 { szSetODBCFolders, NULL},
4286 { szStartServices, ACTION_StartServices },
4287 { szStopServices, ACTION_StopServices },
4288 { szUnpublishComponents, NULL},
4289 { szUnpublishFeatures, NULL},
4290 { szUnregisterClassInfo, NULL},
4291 { szUnregisterComPlus, NULL},
4292 { szUnregisterExtensionInfo, NULL},
4293 { szUnregisterFonts, ACTION_UnregisterFonts },
4294 { szUnregisterMIMEInfo, NULL},
4295 { szUnregisterProgIdInfo, NULL},
4296 { szUnregisterTypeLibraries, NULL},
4297 { szValidateProductID, NULL},
4298 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4299 { szWriteIniValues, ACTION_WriteIniValues },
4300 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4301 { NULL, NULL},