msi: Don't crash if there's no script present when we try execute one.
[wine/multimedia.git] / dlls / msi / action.c
blob6f4ce410c96d9ef6fd81cda618370409cca0a1aa
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 static UINT msi_apply_transforms( MSIPACKAGE *package )
574 static const WCHAR szTransforms[] = {
575 'T','R','A','N','S','F','O','R','M','S',0 };
576 LPWSTR xform_list, *xforms;
577 UINT i, r = ERROR_SUCCESS;
579 xform_list = msi_dup_property( package, szTransforms );
580 xforms = msi_split_string( xform_list, ';' );
582 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
584 if (xforms[i][0] == ':')
585 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
586 else
587 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
590 msi_free( xforms );
591 msi_free( xform_list );
593 return r;
596 /****************************************************
597 * TOP level entry points
598 *****************************************************/
600 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
601 LPCWSTR szCommandLine )
603 UINT rc;
604 BOOL ui = FALSE;
605 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
606 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
607 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
609 MSI_SetPropertyW(package, szAction, szInstall);
611 package->script = msi_alloc(sizeof(MSISCRIPT));
612 memset(package->script,0,sizeof(MSISCRIPT));
614 package->script->InWhatSequence = SEQUENCE_INSTALL;
616 if (szPackagePath)
618 LPWSTR p, check, path;
620 package->PackagePath = strdupW(szPackagePath);
621 path = strdupW(szPackagePath);
622 p = strrchrW(path,'\\');
623 if (p)
625 p++;
626 *p=0;
628 else
630 msi_free(path);
631 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
632 GetCurrentDirectoryW(MAX_PATH,path);
633 strcatW(path,cszbs);
636 check = msi_dup_property( package, cszSourceDir );
637 if (!check)
638 MSI_SetPropertyW(package, cszSourceDir, path);
639 msi_free(check);
640 msi_free(path);
643 msi_parse_command_line( package, szCommandLine );
645 msi_apply_transforms( package );
646 msi_apply_patches( package );
648 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
650 package->script->InWhatSequence |= SEQUENCE_UI;
651 rc = ACTION_ProcessUISequence(package);
652 ui = TRUE;
653 if (rc == ERROR_SUCCESS)
655 package->script->InWhatSequence |= SEQUENCE_EXEC;
656 rc = ACTION_ProcessExecSequence(package,TRUE);
659 else
660 rc = ACTION_ProcessExecSequence(package,FALSE);
662 if (rc == -1)
664 /* install was halted but should be considered a success */
665 rc = ERROR_SUCCESS;
668 package->script->CurrentlyScripting= FALSE;
670 /* process the ending type action */
671 if (rc == ERROR_SUCCESS)
672 ACTION_PerformActionSequence(package,-1,ui);
673 else if (rc == ERROR_INSTALL_USEREXIT)
674 ACTION_PerformActionSequence(package,-2,ui);
675 else if (rc == ERROR_INSTALL_SUSPEND)
676 ACTION_PerformActionSequence(package,-4,ui);
677 else /* failed */
678 ACTION_PerformActionSequence(package,-3,ui);
680 /* finish up running custom actions */
681 ACTION_FinishCustomActions(package);
683 return rc;
686 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
688 UINT rc = ERROR_SUCCESS;
689 MSIRECORD * row = 0;
690 static const WCHAR ExecSeqQuery[] =
691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
692 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
693 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
694 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
696 static const WCHAR UISeqQuery[] =
697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
698 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
699 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
700 ' ', '=',' ','%','i',0};
702 if (UI)
703 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
704 else
705 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
707 if (row)
709 LPCWSTR action, cond;
711 TRACE("Running the actions\n");
713 /* check conditions */
714 cond = MSI_RecordGetString(row,2);
715 if (cond)
717 /* this is a hack to skip errors in the condition code */
718 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
719 goto end;
722 action = MSI_RecordGetString(row,1);
723 if (!action)
725 ERR("failed to fetch action\n");
726 rc = ERROR_FUNCTION_FAILED;
727 goto end;
730 if (UI)
731 rc = ACTION_PerformUIAction(package,action);
732 else
733 rc = ACTION_PerformAction(package,action,FALSE);
734 end:
735 msiobj_release(&row->hdr);
737 else
738 rc = ERROR_SUCCESS;
740 return rc;
743 typedef struct {
744 MSIPACKAGE* package;
745 BOOL UI;
746 } iterate_action_param;
748 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
750 iterate_action_param *iap= (iterate_action_param*)param;
751 UINT rc;
752 LPCWSTR cond, action;
754 action = MSI_RecordGetString(row,1);
755 if (!action)
757 ERR("Error is retrieving action name\n");
758 return ERROR_FUNCTION_FAILED;
761 /* check conditions */
762 cond = MSI_RecordGetString(row,2);
763 if (cond)
765 /* this is a hack to skip errors in the condition code */
766 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
768 TRACE("Skipping action: %s (condition is false)\n",
769 debugstr_w(action));
770 return ERROR_SUCCESS;
774 if (iap->UI)
775 rc = ACTION_PerformUIAction(iap->package,action);
776 else
777 rc = ACTION_PerformAction(iap->package,action,FALSE);
779 msi_dialog_check_messages( NULL );
781 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
782 rc = iap->package->CurrentInstallState;
784 if (rc == ERROR_FUNCTION_NOT_CALLED)
785 rc = ERROR_SUCCESS;
787 if (rc != ERROR_SUCCESS)
788 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
790 return rc;
793 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
795 MSIQUERY * view;
796 UINT r;
797 static const WCHAR query[] =
798 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
799 '`','%','s','`',
800 ' ','W','H','E','R','E',' ',
801 '`','S','e','q','u','e','n','c','e','`',' ',
802 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
803 '`','S','e','q','u','e','n','c','e','`',0};
804 iterate_action_param iap;
807 * FIXME: probably should be checking UILevel in the
808 * ACTION_PerformUIAction/ACTION_PerformAction
809 * rather than saving the UI level here. Those
810 * two functions can be merged too.
812 iap.package = package;
813 iap.UI = TRUE;
815 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
817 r = MSI_OpenQuery( package->db, &view, query, szTable );
818 if (r == ERROR_SUCCESS)
820 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
821 msiobj_release(&view->hdr);
824 return r;
827 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
829 MSIQUERY * view;
830 UINT rc;
831 static const WCHAR ExecSeqQuery[] =
832 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
833 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
834 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
835 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
836 'O','R','D','E','R',' ', 'B','Y',' ',
837 '`','S','e','q','u','e','n','c','e','`',0 };
838 MSIRECORD * row = 0;
839 static const WCHAR IVQuery[] =
840 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
841 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
842 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
843 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
844 ' ','\'', 'I','n','s','t','a','l','l',
845 'V','a','l','i','d','a','t','e','\'', 0};
846 INT seq = 0;
847 iterate_action_param iap;
849 iap.package = package;
850 iap.UI = FALSE;
852 if (package->script->ExecuteSequenceRun)
854 TRACE("Execute Sequence already Run\n");
855 return ERROR_SUCCESS;
858 package->script->ExecuteSequenceRun = TRUE;
860 /* get the sequence number */
861 if (UIran)
863 row = MSI_QueryGetRecord(package->db, IVQuery);
864 if( !row )
865 return ERROR_FUNCTION_FAILED;
866 seq = MSI_RecordGetInteger(row,1);
867 msiobj_release(&row->hdr);
870 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
871 if (rc == ERROR_SUCCESS)
873 TRACE("Running the actions\n");
875 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
876 msiobj_release(&view->hdr);
879 return rc;
882 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
884 MSIQUERY * view;
885 UINT rc;
886 static const WCHAR ExecSeqQuery [] =
887 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
888 '`','I','n','s','t','a','l','l',
889 'U','I','S','e','q','u','e','n','c','e','`',
890 ' ','W','H','E','R','E',' ',
891 '`','S','e','q','u','e','n','c','e','`',' ',
892 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
893 '`','S','e','q','u','e','n','c','e','`',0};
894 iterate_action_param iap;
896 iap.package = package;
897 iap.UI = TRUE;
899 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
901 if (rc == ERROR_SUCCESS)
903 TRACE("Running the actions\n");
905 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
906 msiobj_release(&view->hdr);
909 return rc;
912 /********************************************************
913 * ACTION helper functions and functions that perform the actions
914 *******************************************************/
915 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
916 UINT* rc, BOOL force )
918 BOOL ret = FALSE;
919 BOOL run = force;
920 int i;
922 if (!package)
924 ERR("package was null!\n");
925 return FALSE;
928 if (!run && !package->script->CurrentlyScripting)
929 run = TRUE;
931 if (!run)
933 if (strcmpW(action,szInstallFinalize) == 0 ||
934 strcmpW(action,szInstallExecute) == 0 ||
935 strcmpW(action,szInstallExecuteAgain) == 0)
936 run = TRUE;
939 i = 0;
940 while (StandardActions[i].action != NULL)
942 if (strcmpW(StandardActions[i].action, action)==0)
944 if (!run)
946 ui_actioninfo(package, action, TRUE, 0);
947 *rc = schedule_action(package,INSTALL_SCRIPT,action);
948 ui_actioninfo(package, action, FALSE, *rc);
950 else
952 ui_actionstart(package, action);
953 if (StandardActions[i].handler)
955 *rc = StandardActions[i].handler(package);
957 else
959 FIXME("unhandled standard action %s\n",debugstr_w(action));
960 *rc = ERROR_SUCCESS;
963 ret = TRUE;
964 break;
966 i++;
968 return ret;
971 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
972 UINT* rc, BOOL force )
974 BOOL ret=FALSE;
975 UINT arc;
977 arc = ACTION_CustomAction(package,action, force);
979 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
981 *rc = arc;
982 ret = TRUE;
984 return ret;
988 * A lot of actions are really important even if they don't do anything
989 * explicit... Lots of properties are set at the beginning of the installation
990 * CostFinalize does a bunch of work to translate the directories and such
992 * But until I get write access to the database that is hard, so I am going to
993 * hack it to see if I can get something to run.
995 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
997 UINT rc = ERROR_SUCCESS;
998 BOOL handled;
1000 TRACE("Performing action (%s)\n",debugstr_w(action));
1002 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1004 if (!handled)
1005 handled = ACTION_HandleCustomAction(package, action, &rc, force);
1007 if (!handled)
1009 FIXME("unhandled msi action %s\n",debugstr_w(action));
1010 rc = ERROR_FUNCTION_NOT_CALLED;
1013 return rc;
1016 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1018 UINT rc = ERROR_SUCCESS;
1019 BOOL handled = FALSE;
1021 TRACE("Performing action (%s)\n",debugstr_w(action));
1023 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1025 if (!handled)
1026 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1028 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1029 handled = TRUE;
1031 if (!handled)
1033 FIXME("unhandled msi action %s\n",debugstr_w(action));
1034 rc = ERROR_FUNCTION_NOT_CALLED;
1037 return rc;
1042 * Actual Action Handlers
1045 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1047 MSIPACKAGE *package = (MSIPACKAGE*)param;
1048 LPCWSTR dir;
1049 LPWSTR full_path;
1050 MSIRECORD *uirow;
1051 MSIFOLDER *folder;
1053 dir = MSI_RecordGetString(row,1);
1054 if (!dir)
1056 ERR("Unable to get folder id\n");
1057 return ERROR_SUCCESS;
1060 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1061 if (!full_path)
1063 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1064 return ERROR_SUCCESS;
1067 TRACE("Folder is %s\n",debugstr_w(full_path));
1069 /* UI stuff */
1070 uirow = MSI_CreateRecord(1);
1071 MSI_RecordSetStringW(uirow,1,full_path);
1072 ui_actiondata(package,szCreateFolders,uirow);
1073 msiobj_release( &uirow->hdr );
1075 if (folder->State == 0)
1076 create_full_pathW(full_path);
1078 folder->State = 3;
1080 msi_free(full_path);
1081 return ERROR_SUCCESS;
1084 /* FIXME: probably should merge this with the above function */
1085 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1087 UINT rc = ERROR_SUCCESS;
1088 MSIFOLDER *folder;
1089 LPWSTR install_path;
1091 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1092 if (!install_path)
1093 return ERROR_FUNCTION_FAILED;
1095 /* create the path */
1096 if (folder->State == 0)
1098 create_full_pathW(install_path);
1099 folder->State = 2;
1101 msi_free(install_path);
1103 return rc;
1106 UINT msi_create_component_directories( MSIPACKAGE *package )
1108 MSICOMPONENT *comp;
1110 /* create all the folders required by the components are going to install */
1111 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1113 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1114 continue;
1115 msi_create_directory( package, comp->Directory );
1118 return ERROR_SUCCESS;
1122 * Also we cannot enable/disable components either, so for now I am just going
1123 * to do all the directories for all the components.
1125 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1127 static const WCHAR ExecSeqQuery[] =
1128 {'S','E','L','E','C','T',' ',
1129 '`','D','i','r','e','c','t','o','r','y','_','`',
1130 ' ','F','R','O','M',' ',
1131 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1132 UINT rc;
1133 MSIQUERY *view;
1135 /* create all the empty folders specified in the CreateFolder table */
1136 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1137 if (rc != ERROR_SUCCESS)
1138 return ERROR_SUCCESS;
1140 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1141 msiobj_release(&view->hdr);
1143 msi_create_component_directories( package );
1145 return rc;
1148 static MSICOMPONENT* load_component( MSIRECORD * row )
1150 MSICOMPONENT *comp;
1152 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1153 if (!comp)
1154 return comp;
1156 /* fill in the data */
1157 comp->Component = msi_dup_record_field( row, 1 );
1159 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1161 comp->ComponentId = msi_dup_record_field( row, 2 );
1162 comp->Directory = msi_dup_record_field( row, 3 );
1163 comp->Attributes = MSI_RecordGetInteger(row,4);
1164 comp->Condition = msi_dup_record_field( row, 5 );
1165 comp->KeyPath = msi_dup_record_field( row, 6 );
1167 comp->Installed = INSTALLSTATE_ABSENT;
1168 comp->Action = INSTALLSTATE_UNKNOWN;
1169 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1171 comp->Enabled = TRUE;
1173 return comp;
1176 typedef struct {
1177 MSIPACKAGE *package;
1178 MSIFEATURE *feature;
1179 } _ilfs;
1181 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1183 ComponentList *cl;
1185 cl = msi_alloc( sizeof (*cl) );
1186 if ( !cl )
1187 return ERROR_NOT_ENOUGH_MEMORY;
1188 cl->component = comp;
1189 list_add_tail( &feature->Components, &cl->entry );
1191 return ERROR_SUCCESS;
1194 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1196 _ilfs* ilfs= (_ilfs*)param;
1197 MSIPACKAGE *package = ilfs->package;
1198 MSIFEATURE *feature = ilfs->feature;
1199 MSICOMPONENT *comp;
1201 comp = load_component( row );
1202 if (!comp)
1203 return ERROR_FUNCTION_FAILED;
1205 list_add_tail( &package->components, &comp->entry );
1206 add_feature_component( feature, comp );
1208 TRACE("Loaded new component %p\n", comp);
1210 return ERROR_SUCCESS;
1213 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1215 _ilfs* ilfs= (_ilfs*)param;
1216 LPCWSTR component;
1217 DWORD rc;
1218 MSICOMPONENT *comp;
1219 MSIQUERY * view;
1220 static const WCHAR Query[] =
1221 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1222 '`','C','o','m','p','o','n','e','n','t','`',' ',
1223 'W','H','E','R','E',' ',
1224 '`','C','o','m','p','o','n','e','n','t','`',' ',
1225 '=','\'','%','s','\'',0};
1227 component = MSI_RecordGetString(row,1);
1229 /* check to see if the component is already loaded */
1230 comp = get_loaded_component( ilfs->package, component );
1231 if (comp)
1233 TRACE("Component %s already loaded\n", debugstr_w(component) );
1234 add_feature_component( ilfs->feature, comp );
1235 return ERROR_SUCCESS;
1238 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1239 if (rc != ERROR_SUCCESS)
1240 return ERROR_SUCCESS;
1242 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1243 msiobj_release( &view->hdr );
1245 return ERROR_SUCCESS;
1248 static UINT load_feature(MSIRECORD * row, LPVOID param)
1250 MSIPACKAGE* package = (MSIPACKAGE*)param;
1251 MSIFEATURE* feature;
1252 static const WCHAR Query1[] =
1253 {'S','E','L','E','C','T',' ',
1254 '`','C','o','m','p','o','n','e','n','t','_','`',
1255 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1256 'C','o','m','p','o','n','e','n','t','s','`',' ',
1257 'W','H','E','R','E',' ',
1258 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1259 MSIQUERY * view;
1260 UINT rc;
1261 _ilfs ilfs;
1263 /* fill in the data */
1265 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1266 if (!feature)
1267 return ERROR_NOT_ENOUGH_MEMORY;
1269 list_init( &feature->Components );
1271 feature->Feature = msi_dup_record_field( row, 1 );
1273 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1275 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1276 feature->Title = msi_dup_record_field( row, 3 );
1277 feature->Description = msi_dup_record_field( row, 4 );
1279 if (!MSI_RecordIsNull(row,5))
1280 feature->Display = MSI_RecordGetInteger(row,5);
1282 feature->Level= MSI_RecordGetInteger(row,6);
1283 feature->Directory = msi_dup_record_field( row, 7 );
1284 feature->Attributes = MSI_RecordGetInteger(row,8);
1286 feature->Installed = INSTALLSTATE_ABSENT;
1287 feature->Action = INSTALLSTATE_UNKNOWN;
1288 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1290 list_add_tail( &package->features, &feature->entry );
1292 /* load feature components */
1294 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1295 if (rc != ERROR_SUCCESS)
1296 return ERROR_SUCCESS;
1298 ilfs.package = package;
1299 ilfs.feature = feature;
1301 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1302 msiobj_release(&view->hdr);
1304 return ERROR_SUCCESS;
1307 static UINT load_file(MSIRECORD *row, LPVOID param)
1309 MSIPACKAGE* package = (MSIPACKAGE*)param;
1310 LPCWSTR component;
1311 MSIFILE *file;
1313 /* fill in the data */
1315 file = msi_alloc_zero( sizeof (MSIFILE) );
1316 if (!file)
1317 return ERROR_NOT_ENOUGH_MEMORY;
1319 file->File = msi_dup_record_field( row, 1 );
1321 component = MSI_RecordGetString( row, 2 );
1322 file->Component = get_loaded_component( package, component );
1324 if (!file->Component)
1325 ERR("Unfound Component %s\n",debugstr_w(component));
1327 file->FileName = msi_dup_record_field( row, 3 );
1328 reduce_to_longfilename( file->FileName );
1330 file->ShortName = msi_dup_record_field( row, 3 );
1331 reduce_to_shortfilename( file->ShortName );
1333 file->FileSize = MSI_RecordGetInteger( row, 4 );
1334 file->Version = msi_dup_record_field( row, 5 );
1335 file->Language = msi_dup_record_field( row, 6 );
1336 file->Attributes = MSI_RecordGetInteger( row, 7 );
1337 file->Sequence = MSI_RecordGetInteger( row, 8 );
1339 file->state = msifs_invalid;
1341 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1343 list_add_tail( &package->files, &file->entry );
1345 return ERROR_SUCCESS;
1348 static UINT load_all_files(MSIPACKAGE *package)
1350 MSIQUERY * view;
1351 UINT rc;
1352 static const WCHAR Query[] =
1353 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1354 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1355 '`','S','e','q','u','e','n','c','e','`', 0};
1357 if (!package)
1358 return ERROR_INVALID_HANDLE;
1360 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1361 if (rc != ERROR_SUCCESS)
1362 return ERROR_SUCCESS;
1364 rc = MSI_IterateRecords(view, NULL, load_file, package);
1365 msiobj_release(&view->hdr);
1367 return ERROR_SUCCESS;
1372 * I am not doing any of the costing functionality yet.
1373 * Mostly looking at doing the Component and Feature loading
1375 * The native MSI does A LOT of modification to tables here. Mostly adding
1376 * a lot of temporary columns to the Feature and Component tables.
1378 * note: Native msi also tracks the short filename. But I am only going to
1379 * track the long ones. Also looking at this directory table
1380 * it appears that the directory table does not get the parents
1381 * resolved base on property only based on their entries in the
1382 * directory table.
1384 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1386 MSIQUERY * view;
1387 UINT rc;
1388 static const WCHAR Query_all[] =
1389 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1390 '`','F','e','a','t','u','r','e','`',0};
1391 static const WCHAR szCosting[] =
1392 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1393 static const WCHAR szZero[] = { '0', 0 };
1395 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1396 return ERROR_SUCCESS;
1398 MSI_SetPropertyW(package, szCosting, szZero);
1399 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1401 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1402 if (rc != ERROR_SUCCESS)
1403 return rc;
1405 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1406 msiobj_release(&view->hdr);
1408 load_all_files(package);
1410 return ERROR_SUCCESS;
1413 static UINT execute_script(MSIPACKAGE *package, UINT script )
1415 int i;
1416 UINT rc = ERROR_SUCCESS;
1418 TRACE("Executing Script %i\n",script);
1420 if (!package->script)
1422 ERR("no script!\n");
1423 return ERROR_FUNCTION_FAILED;
1426 for (i = 0; i < package->script->ActionCount[script]; i++)
1428 LPWSTR action;
1429 action = package->script->Actions[script][i];
1430 ui_actionstart(package, action);
1431 TRACE("Executing Action (%s)\n",debugstr_w(action));
1432 rc = ACTION_PerformAction(package, action, TRUE);
1433 msi_free(package->script->Actions[script][i]);
1434 if (rc != ERROR_SUCCESS)
1435 break;
1437 msi_free(package->script->Actions[script]);
1439 package->script->ActionCount[script] = 0;
1440 package->script->Actions[script] = NULL;
1441 return rc;
1444 static UINT ACTION_FileCost(MSIPACKAGE *package)
1446 return ERROR_SUCCESS;
1450 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1452 static const WCHAR Query[] =
1453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1454 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1455 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1456 ' ','=',' ','\'','%','s','\'',
1458 LPWSTR ptargetdir, targetdir, srcdir;
1459 LPCWSTR parent;
1460 LPWSTR shortname = NULL;
1461 MSIRECORD * row = 0;
1462 MSIFOLDER *folder;
1464 TRACE("Looking for dir %s\n",debugstr_w(dir));
1466 folder = get_loaded_folder( package, dir );
1467 if (folder)
1468 return folder;
1470 TRACE("Working to load %s\n",debugstr_w(dir));
1472 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1473 if (!folder)
1474 return NULL;
1476 folder->Directory = strdupW(dir);
1478 row = MSI_QueryGetRecord(package->db, Query, dir);
1479 if (!row)
1480 return NULL;
1482 ptargetdir = targetdir = msi_dup_record_field(row,3);
1484 /* split src and target dir */
1485 if (strchrW(targetdir,':'))
1487 srcdir=strchrW(targetdir,':');
1488 *srcdir=0;
1489 srcdir ++;
1491 else
1492 srcdir=NULL;
1494 /* for now only pick long filename versions */
1495 if (strchrW(targetdir,'|'))
1497 shortname = targetdir;
1498 targetdir = strchrW(targetdir,'|');
1499 *targetdir = 0;
1500 targetdir ++;
1502 /* for the sourcedir pick the short filename */
1503 if (srcdir && strchrW(srcdir,'|'))
1505 LPWSTR p = strchrW(srcdir,'|');
1506 *p = 0;
1509 /* now check for root dirs */
1510 if (targetdir[0] == '.' && targetdir[1] == 0)
1511 targetdir = NULL;
1513 if (targetdir)
1515 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1516 msi_free( folder->TargetDefault);
1517 folder->TargetDefault = strdupW(targetdir);
1520 if (srcdir)
1521 folder->SourceDefault = strdupW(srcdir);
1522 else if (shortname)
1523 folder->SourceDefault = strdupW(shortname);
1524 else if (targetdir)
1525 folder->SourceDefault = strdupW(targetdir);
1526 msi_free(ptargetdir);
1527 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1529 parent = MSI_RecordGetString(row,2);
1530 if (parent)
1532 folder->Parent = load_folder( package, parent );
1533 if ( folder->Parent )
1534 TRACE("loaded parent %p %s\n", folder->Parent,
1535 debugstr_w(folder->Parent->Directory));
1536 else
1537 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1540 folder->Property = msi_dup_property( package, dir );
1542 msiobj_release(&row->hdr);
1544 list_add_tail( &package->folders, &folder->entry );
1546 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1548 return folder;
1551 /* scan for and update current install states */
1552 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1554 MSICOMPONENT *comp;
1555 MSIFEATURE *feature;
1557 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1559 INSTALLSTATE res;
1560 res = MsiGetComponentPathW( package->ProductCode,
1561 comp->ComponentId, NULL, NULL);
1562 if (res < 0)
1563 res = INSTALLSTATE_ABSENT;
1564 comp->Installed = res;
1567 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1569 ComponentList *cl;
1570 INSTALLSTATE res = -10;
1572 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1574 comp= cl->component;
1576 if (res == -10)
1577 res = comp->Installed;
1578 else
1580 if (res == comp->Installed)
1581 continue;
1583 if (res != comp->Installed)
1584 res = INSTALLSTATE_INCOMPLETE;
1587 feature->Installed = res;
1591 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1592 INSTALLSTATE state)
1594 static const WCHAR all[]={'A','L','L',0};
1595 LPWSTR override;
1596 MSIFEATURE *feature;
1598 override = msi_dup_property( package, property );
1599 if (!override)
1600 return FALSE;
1602 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1604 if (strcmpiW(override,all)==0)
1606 feature->ActionRequest= state;
1607 feature->Action = state;
1609 else
1611 LPWSTR ptr = override;
1612 LPWSTR ptr2 = strchrW(override,',');
1614 while (ptr)
1616 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1617 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1619 feature->ActionRequest= state;
1620 feature->Action = state;
1621 break;
1623 if (ptr2)
1625 ptr=ptr2+1;
1626 ptr2 = strchrW(ptr,',');
1628 else
1629 break;
1633 msi_free(override);
1635 return TRUE;
1638 static UINT SetFeatureStates(MSIPACKAGE *package)
1640 int install_level;
1641 static const WCHAR szlevel[] =
1642 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1643 static const WCHAR szAddLocal[] =
1644 {'A','D','D','L','O','C','A','L',0};
1645 static const WCHAR szRemove[] =
1646 {'R','E','M','O','V','E',0};
1647 static const WCHAR szReinstall[] =
1648 {'R','E','I','N','S','T','A','L','L',0};
1649 BOOL override = FALSE;
1650 MSICOMPONENT* component;
1651 MSIFEATURE *feature;
1654 /* I do not know if this is where it should happen.. but */
1656 TRACE("Checking Install Level\n");
1658 install_level = msi_get_property_int( package, szlevel, 1 );
1660 /* ok hereis the _real_ rub
1661 * all these activation/deactivation things happen in order and things
1662 * later on the list override things earlier on the list.
1663 * 1) INSTALLLEVEL processing
1664 * 2) ADDLOCAL
1665 * 3) REMOVE
1666 * 4) ADDSOURCE
1667 * 5) ADDDEFAULT
1668 * 6) REINSTALL
1669 * 7) COMPADDLOCAL
1670 * 8) COMPADDSOURCE
1671 * 9) FILEADDLOCAL
1672 * 10) FILEADDSOURCE
1673 * 11) FILEADDDEFAULT
1674 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1675 * ignored for all the features. seems strange, especially since it is not
1676 * documented anywhere, but it is how it works.
1678 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1679 * REMOVE are the big ones, since we don't handle administrative installs
1680 * yet anyway.
1682 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1683 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1684 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1686 if (!override)
1688 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1690 BOOL feature_state = ((feature->Level > 0) &&
1691 (feature->Level <= install_level));
1693 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1695 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1697 feature->ActionRequest = INSTALLSTATE_SOURCE;
1698 feature->Action = INSTALLSTATE_SOURCE;
1700 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1702 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1703 feature->Action = INSTALLSTATE_ADVERTISED;
1705 else
1707 feature->ActionRequest = INSTALLSTATE_LOCAL;
1708 feature->Action = INSTALLSTATE_LOCAL;
1713 else
1715 /* set the Preselected Property */
1716 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1717 static const WCHAR szOne[] = { '1', 0 };
1719 MSI_SetPropertyW(package,szPreselected,szOne);
1723 * now we want to enable or disable components base on feature
1726 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1728 ComponentList *cl;
1730 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1731 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1732 feature->ActionRequest);
1734 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1736 component = cl->component;
1738 if (!component->Enabled)
1740 component->Action = INSTALLSTATE_UNKNOWN;
1741 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1743 else
1745 if (feature->Action == INSTALLSTATE_LOCAL)
1747 component->Action = INSTALLSTATE_LOCAL;
1748 component->ActionRequest = INSTALLSTATE_LOCAL;
1750 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1752 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1753 (component->Action == INSTALLSTATE_ABSENT) ||
1754 (component->Action == INSTALLSTATE_ADVERTISED))
1757 component->Action = INSTALLSTATE_SOURCE;
1758 component->ActionRequest = INSTALLSTATE_SOURCE;
1761 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1763 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1764 (component->Action == INSTALLSTATE_ABSENT))
1767 component->Action = INSTALLSTATE_ADVERTISED;
1768 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1771 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1773 if (component->Action == INSTALLSTATE_UNKNOWN)
1775 component->Action = INSTALLSTATE_ABSENT;
1776 component->ActionRequest = INSTALLSTATE_ABSENT;
1783 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1785 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1786 debugstr_w(component->Component), component->Installed,
1787 component->Action, component->ActionRequest);
1791 return ERROR_SUCCESS;
1794 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1796 MSIPACKAGE *package = (MSIPACKAGE*)param;
1797 LPCWSTR name;
1798 LPWSTR path;
1800 name = MSI_RecordGetString(row,1);
1802 /* This helper function now does ALL the work */
1803 TRACE("Dir %s ...\n",debugstr_w(name));
1804 load_folder(package,name);
1805 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1806 TRACE("resolves to %s\n",debugstr_w(path));
1807 msi_free(path);
1809 return ERROR_SUCCESS;
1812 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1814 MSIPACKAGE *package = (MSIPACKAGE*)param;
1815 LPCWSTR name;
1816 MSIFEATURE *feature;
1818 name = MSI_RecordGetString( row, 1 );
1820 feature = get_loaded_feature( package, name );
1821 if (!feature)
1822 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1823 else
1825 LPCWSTR Condition;
1826 Condition = MSI_RecordGetString(row,3);
1828 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1830 int level = MSI_RecordGetInteger(row,2);
1831 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1832 feature->Level = level;
1835 return ERROR_SUCCESS;
1840 * A lot is done in this function aside from just the costing.
1841 * The costing needs to be implemented at some point but for now I am going
1842 * to focus on the directory building
1845 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1847 static const WCHAR ExecSeqQuery[] =
1848 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1849 '`','D','i','r','e','c','t','o','r','y','`',0};
1850 static const WCHAR ConditionQuery[] =
1851 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1852 '`','C','o','n','d','i','t','i','o','n','`',0};
1853 static const WCHAR szCosting[] =
1854 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1855 static const WCHAR szlevel[] =
1856 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1857 static const WCHAR szOne[] = { '1', 0 };
1858 MSICOMPONENT *comp;
1859 MSIFILE *file;
1860 UINT rc;
1861 MSIQUERY * view;
1862 LPWSTR level;
1864 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1865 return ERROR_SUCCESS;
1867 TRACE("Building Directory properties\n");
1869 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1870 if (rc == ERROR_SUCCESS)
1872 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1873 package);
1874 msiobj_release(&view->hdr);
1877 TRACE("File calculations\n");
1879 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1881 MSICOMPONENT* comp = file->Component;
1882 LPWSTR p;
1884 if (!comp)
1885 continue;
1887 /* calculate target */
1888 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1890 msi_free(file->TargetPath);
1892 TRACE("file %s is named %s\n",
1893 debugstr_w(file->File),debugstr_w(file->FileName));
1895 file->TargetPath = build_directory_name(2, p, file->FileName);
1897 msi_free(p);
1899 TRACE("file %s resolves to %s\n",
1900 debugstr_w(file->File),debugstr_w(file->TargetPath));
1902 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1904 file->state = msifs_missing;
1905 comp->Cost += file->FileSize;
1906 continue;
1909 if (file->Version)
1911 DWORD handle;
1912 DWORD versize;
1913 UINT sz;
1914 LPVOID version;
1915 static WCHAR name[] = {'\\',0};
1916 static const WCHAR name_fmt[] =
1917 {'%','u','.','%','u','.','%','u','.','%','u',0};
1918 WCHAR filever[0x100];
1919 VS_FIXEDFILEINFO *lpVer;
1921 TRACE("Version comparison..\n");
1922 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1923 version = msi_alloc(versize);
1924 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1926 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1928 sprintfW(filever,name_fmt,
1929 HIWORD(lpVer->dwFileVersionMS),
1930 LOWORD(lpVer->dwFileVersionMS),
1931 HIWORD(lpVer->dwFileVersionLS),
1932 LOWORD(lpVer->dwFileVersionLS));
1934 TRACE("new %s old %s\n", debugstr_w(file->Version),
1935 debugstr_w(filever));
1936 if (strcmpiW(filever,file->Version)<0)
1938 file->state = msifs_overwrite;
1939 /* FIXME: cost should be diff in size */
1940 comp->Cost += file->FileSize;
1942 else
1943 file->state = msifs_present;
1944 msi_free(version);
1946 else
1947 file->state = msifs_present;
1950 TRACE("Evaluating Condition Table\n");
1952 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1953 if (rc == ERROR_SUCCESS)
1955 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1956 package);
1957 msiobj_release(&view->hdr);
1960 TRACE("Enabling or Disabling Components\n");
1961 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1963 if (comp->Condition)
1965 if (MSI_EvaluateConditionW(package,
1966 comp->Condition) == MSICONDITION_FALSE)
1968 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1969 comp->Enabled = FALSE;
1974 MSI_SetPropertyW(package,szCosting,szOne);
1975 /* set default run level if not set */
1976 level = msi_dup_property( package, szlevel );
1977 if (!level)
1978 MSI_SetPropertyW(package,szlevel, szOne);
1979 msi_free(level);
1981 ACTION_UpdateInstallStates(package);
1983 return SetFeatureStates(package);
1986 /* OK this value is "interpreted" and then formatted based on the
1987 first few characters */
1988 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1989 DWORD *size)
1991 LPSTR data = NULL;
1992 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1994 if (value[1]=='x')
1996 LPWSTR ptr;
1997 CHAR byte[5];
1998 LPWSTR deformated = NULL;
1999 int count;
2001 deformat_string(package, &value[2], &deformated);
2003 /* binary value type */
2004 ptr = deformated;
2005 *type = REG_BINARY;
2006 if (strlenW(ptr)%2)
2007 *size = (strlenW(ptr)/2)+1;
2008 else
2009 *size = strlenW(ptr)/2;
2011 data = msi_alloc(*size);
2013 byte[0] = '0';
2014 byte[1] = 'x';
2015 byte[4] = 0;
2016 count = 0;
2017 /* if uneven pad with a zero in front */
2018 if (strlenW(ptr)%2)
2020 byte[2]= '0';
2021 byte[3]= *ptr;
2022 ptr++;
2023 data[count] = (BYTE)strtol(byte,NULL,0);
2024 count ++;
2025 TRACE("Uneven byte count\n");
2027 while (*ptr)
2029 byte[2]= *ptr;
2030 ptr++;
2031 byte[3]= *ptr;
2032 ptr++;
2033 data[count] = (BYTE)strtol(byte,NULL,0);
2034 count ++;
2036 msi_free(deformated);
2038 TRACE("Data %li bytes(%i)\n",*size,count);
2040 else
2042 LPWSTR deformated;
2043 LPWSTR p;
2044 DWORD d = 0;
2045 deformat_string(package, &value[1], &deformated);
2047 *type=REG_DWORD;
2048 *size = sizeof(DWORD);
2049 data = msi_alloc(*size);
2050 p = deformated;
2051 if (*p == '-')
2052 p++;
2053 while (*p)
2055 if ( (*p < '0') || (*p > '9') )
2056 break;
2057 d *= 10;
2058 d += (*p - '0');
2059 p++;
2061 if (deformated[0] == '-')
2062 d = -d;
2063 *(LPDWORD)data = d;
2064 TRACE("DWORD %li\n",*(LPDWORD)data);
2066 msi_free(deformated);
2069 else
2071 static const WCHAR szMulti[] = {'[','~',']',0};
2072 LPCWSTR ptr;
2073 *type=REG_SZ;
2075 if (value[0]=='#')
2077 if (value[1]=='%')
2079 ptr = &value[2];
2080 *type=REG_EXPAND_SZ;
2082 else
2083 ptr = &value[1];
2085 else
2086 ptr=value;
2088 if (strstrW(value,szMulti))
2089 *type = REG_MULTI_SZ;
2091 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2093 return data;
2096 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2098 MSIPACKAGE *package = (MSIPACKAGE*)param;
2099 static const WCHAR szHCR[] =
2100 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2101 'R','O','O','T','\\',0};
2102 static const WCHAR szHCU[] =
2103 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2104 'U','S','E','R','\\',0};
2105 static const WCHAR szHLM[] =
2106 {'H','K','E','Y','_','L','O','C','A','L','_',
2107 'M','A','C','H','I','N','E','\\',0};
2108 static const WCHAR szHU[] =
2109 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2111 LPSTR value_data = NULL;
2112 HKEY root_key, hkey;
2113 DWORD type,size;
2114 LPWSTR deformated;
2115 LPCWSTR szRoot, component, name, key, value;
2116 MSICOMPONENT *comp;
2117 MSIRECORD * uirow;
2118 LPWSTR uikey;
2119 INT root;
2120 BOOL check_first = FALSE;
2121 UINT rc;
2123 ui_progress(package,2,0,0,0);
2125 value = NULL;
2126 key = NULL;
2127 uikey = NULL;
2128 name = NULL;
2130 component = MSI_RecordGetString(row, 6);
2131 comp = get_loaded_component(package,component);
2132 if (!comp)
2133 return ERROR_SUCCESS;
2135 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2137 TRACE("Skipping write due to disabled component %s\n",
2138 debugstr_w(component));
2140 comp->Action = comp->Installed;
2142 return ERROR_SUCCESS;
2145 comp->Action = INSTALLSTATE_LOCAL;
2147 name = MSI_RecordGetString(row, 4);
2148 if( MSI_RecordIsNull(row,5) && name )
2150 /* null values can have special meanings */
2151 if (name[0]=='-' && name[1] == 0)
2152 return ERROR_SUCCESS;
2153 else if ((name[0]=='+' && name[1] == 0) ||
2154 (name[0] == '*' && name[1] == 0))
2155 name = NULL;
2156 check_first = TRUE;
2159 root = MSI_RecordGetInteger(row,2);
2160 key = MSI_RecordGetString(row, 3);
2162 /* get the root key */
2163 switch (root)
2165 case -1:
2167 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2168 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2169 if (all_users && all_users[0] == '1')
2171 root_key = HKEY_LOCAL_MACHINE;
2172 szRoot = szHLM;
2174 else
2176 root_key = HKEY_CURRENT_USER;
2177 szRoot = szHCU;
2179 msi_free(all_users);
2181 break;
2182 case 0: root_key = HKEY_CLASSES_ROOT;
2183 szRoot = szHCR;
2184 break;
2185 case 1: root_key = HKEY_CURRENT_USER;
2186 szRoot = szHCU;
2187 break;
2188 case 2: root_key = HKEY_LOCAL_MACHINE;
2189 szRoot = szHLM;
2190 break;
2191 case 3: root_key = HKEY_USERS;
2192 szRoot = szHU;
2193 break;
2194 default:
2195 ERR("Unknown root %i\n",root);
2196 root_key=NULL;
2197 szRoot = NULL;
2198 break;
2200 if (!root_key)
2201 return ERROR_SUCCESS;
2203 deformat_string(package, key , &deformated);
2204 size = strlenW(deformated) + strlenW(szRoot) + 1;
2205 uikey = msi_alloc(size*sizeof(WCHAR));
2206 strcpyW(uikey,szRoot);
2207 strcatW(uikey,deformated);
2209 if (RegCreateKeyW( root_key, deformated, &hkey))
2211 ERR("Could not create key %s\n",debugstr_w(deformated));
2212 msi_free(deformated);
2213 msi_free(uikey);
2214 return ERROR_SUCCESS;
2216 msi_free(deformated);
2218 value = MSI_RecordGetString(row,5);
2219 if (value)
2220 value_data = parse_value(package, value, &type, &size);
2221 else
2223 static const WCHAR szEmpty[] = {0};
2224 value_data = (LPSTR)strdupW(szEmpty);
2225 size = 0;
2226 type = REG_SZ;
2229 deformat_string(package, name, &deformated);
2231 /* get the double nulls to terminate SZ_MULTI */
2232 if (type == REG_MULTI_SZ)
2233 size +=sizeof(WCHAR);
2235 if (!check_first)
2237 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2238 debugstr_w(uikey));
2239 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2241 else
2243 DWORD sz = 0;
2244 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2245 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2247 TRACE("value %s of %s checked already exists\n",
2248 debugstr_w(deformated), debugstr_w(uikey));
2250 else
2252 TRACE("Checked and setting value %s of %s\n",
2253 debugstr_w(deformated), debugstr_w(uikey));
2254 if (deformated || size)
2255 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2258 RegCloseKey(hkey);
2260 uirow = MSI_CreateRecord(3);
2261 MSI_RecordSetStringW(uirow,2,deformated);
2262 MSI_RecordSetStringW(uirow,1,uikey);
2264 if (type == REG_SZ)
2265 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2266 else
2267 MSI_RecordSetStringW(uirow,3,value);
2269 ui_actiondata(package,szWriteRegistryValues,uirow);
2270 msiobj_release( &uirow->hdr );
2272 msi_free(value_data);
2273 msi_free(deformated);
2274 msi_free(uikey);
2276 return ERROR_SUCCESS;
2279 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2281 UINT rc;
2282 MSIQUERY * view;
2283 static const WCHAR ExecSeqQuery[] =
2284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2285 '`','R','e','g','i','s','t','r','y','`',0 };
2287 if (!package)
2288 return ERROR_INVALID_HANDLE;
2290 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2291 if (rc != ERROR_SUCCESS)
2292 return ERROR_SUCCESS;
2294 /* increment progress bar each time action data is sent */
2295 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2297 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2299 msiobj_release(&view->hdr);
2300 return rc;
2303 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2305 package->script->CurrentlyScripting = TRUE;
2307 return ERROR_SUCCESS;
2311 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2313 MSICOMPONENT *comp;
2314 DWORD progress = 0;
2315 DWORD total = 0;
2316 static const WCHAR q1[]=
2317 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2318 '`','R','e','g','i','s','t','r','y','`',0};
2319 UINT rc;
2320 MSIQUERY * view;
2321 MSIFEATURE *feature;
2322 MSIFILE *file;
2324 TRACE("InstallValidate\n");
2326 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2327 if (rc == ERROR_SUCCESS)
2329 MSI_IterateRecords( view, &progress, NULL, package );
2330 msiobj_release( &view->hdr );
2331 total += progress * REG_PROGRESS_VALUE;
2334 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2335 total += COMPONENT_PROGRESS_VALUE;
2337 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2338 total += file->FileSize;
2340 ui_progress(package,0,total,0,0);
2342 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2344 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2345 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2346 feature->ActionRequest);
2349 return ERROR_SUCCESS;
2352 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2354 MSIPACKAGE* package = (MSIPACKAGE*)param;
2355 LPCWSTR cond = NULL;
2356 LPCWSTR message = NULL;
2357 static const WCHAR title[]=
2358 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2360 cond = MSI_RecordGetString(row,1);
2362 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2364 LPWSTR deformated;
2365 message = MSI_RecordGetString(row,2);
2366 deformat_string(package,message,&deformated);
2367 MessageBoxW(NULL,deformated,title,MB_OK);
2368 msi_free(deformated);
2369 return ERROR_FUNCTION_FAILED;
2372 return ERROR_SUCCESS;
2375 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2377 UINT rc;
2378 MSIQUERY * view = NULL;
2379 static const WCHAR ExecSeqQuery[] =
2380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2381 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2383 TRACE("Checking launch conditions\n");
2385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2386 if (rc != ERROR_SUCCESS)
2387 return ERROR_SUCCESS;
2389 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2390 msiobj_release(&view->hdr);
2392 return rc;
2395 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2398 if (!cmp->KeyPath)
2399 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2401 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2403 MSIRECORD * row = 0;
2404 UINT root,len;
2405 LPWSTR deformated,buffer,deformated_name;
2406 LPCWSTR key,name;
2407 static const WCHAR ExecSeqQuery[] =
2408 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2409 '`','R','e','g','i','s','t','r','y','`',' ',
2410 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2411 ' ','=',' ' ,'\'','%','s','\'',0 };
2412 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2413 static const WCHAR fmt2[]=
2414 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2416 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2417 if (!row)
2418 return NULL;
2420 root = MSI_RecordGetInteger(row,2);
2421 key = MSI_RecordGetString(row, 3);
2422 name = MSI_RecordGetString(row, 4);
2423 deformat_string(package, key , &deformated);
2424 deformat_string(package, name, &deformated_name);
2426 len = strlenW(deformated) + 6;
2427 if (deformated_name)
2428 len+=strlenW(deformated_name);
2430 buffer = msi_alloc( len *sizeof(WCHAR));
2432 if (deformated_name)
2433 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2434 else
2435 sprintfW(buffer,fmt,root,deformated);
2437 msi_free(deformated);
2438 msi_free(deformated_name);
2439 msiobj_release(&row->hdr);
2441 return buffer;
2443 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2445 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2446 return NULL;
2448 else
2450 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2452 if (file)
2453 return strdupW( file->TargetPath );
2455 return NULL;
2458 static HKEY openSharedDLLsKey(void)
2460 HKEY hkey=0;
2461 static const WCHAR path[] =
2462 {'S','o','f','t','w','a','r','e','\\',
2463 'M','i','c','r','o','s','o','f','t','\\',
2464 'W','i','n','d','o','w','s','\\',
2465 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2466 'S','h','a','r','e','d','D','L','L','s',0};
2468 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2469 return hkey;
2472 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2474 HKEY hkey;
2475 DWORD count=0;
2476 DWORD type;
2477 DWORD sz = sizeof(count);
2478 DWORD rc;
2480 hkey = openSharedDLLsKey();
2481 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2482 if (rc != ERROR_SUCCESS)
2483 count = 0;
2484 RegCloseKey(hkey);
2485 return count;
2488 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2490 HKEY hkey;
2492 hkey = openSharedDLLsKey();
2493 if (count > 0)
2494 msi_reg_set_val_dword( hkey, path, count );
2495 else
2496 RegDeleteValueW(hkey,path);
2497 RegCloseKey(hkey);
2498 return count;
2502 * Return TRUE if the count should be written out and FALSE if not
2504 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2506 MSIFEATURE *feature;
2507 INT count = 0;
2508 BOOL write = FALSE;
2510 /* only refcount DLLs */
2511 if (comp->KeyPath == NULL ||
2512 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2513 comp->Attributes & msidbComponentAttributesODBCDataSource)
2514 write = FALSE;
2515 else
2517 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2518 write = (count > 0);
2520 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2521 write = TRUE;
2524 /* increment counts */
2525 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2527 ComponentList *cl;
2529 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2530 continue;
2532 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2534 if ( cl->component == comp )
2535 count++;
2539 /* decrement counts */
2540 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2542 ComponentList *cl;
2544 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2545 continue;
2547 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2549 if ( cl->component == comp )
2550 count--;
2554 /* ref count all the files in the component */
2555 if (write)
2557 MSIFILE *file;
2559 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2561 if (file->Component == comp)
2562 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2566 /* add a count for permenent */
2567 if (comp->Attributes & msidbComponentAttributesPermanent)
2568 count ++;
2570 comp->RefCount = count;
2572 if (write)
2573 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2577 * Ok further analysis makes me think that this work is
2578 * actually done in the PublishComponents and PublishFeatures
2579 * step, and not here. It appears like the keypath and all that is
2580 * resolved in this step, however actually written in the Publish steps.
2581 * But we will leave it here for now because it is unclear
2583 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2585 WCHAR squished_pc[GUID_SIZE];
2586 WCHAR squished_cc[GUID_SIZE];
2587 UINT rc;
2588 MSICOMPONENT *comp;
2589 HKEY hkey=0,hkey2=0;
2591 /* writes the Component and Features values to the registry */
2593 rc = MSIREG_OpenComponents(&hkey);
2594 if (rc != ERROR_SUCCESS)
2595 goto end;
2597 squash_guid(package->ProductCode,squished_pc);
2598 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2600 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2602 ui_progress(package,2,0,0,0);
2603 if (comp->ComponentId)
2605 MSIRECORD * uirow;
2607 squash_guid(comp->ComponentId,squished_cc);
2609 msi_free(comp->FullKeypath);
2610 comp->FullKeypath = resolve_keypath( package, comp );
2612 /* do the refcounting */
2613 ACTION_RefCountComponent( package, comp );
2615 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2616 debugstr_w(comp->Component),
2617 debugstr_w(squished_cc),
2618 debugstr_w(comp->FullKeypath),
2619 comp->RefCount);
2621 * Write the keypath out if the component is to be registered
2622 * and delete the key if the component is to be deregistered
2624 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2626 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2627 if (rc != ERROR_SUCCESS)
2628 continue;
2630 if (comp->FullKeypath)
2632 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2634 if (comp->Attributes & msidbComponentAttributesPermanent)
2636 static const WCHAR szPermKey[] =
2637 { '0','0','0','0','0','0','0','0','0','0','0','0',
2638 '0','0','0','0','0','0','0','0','0','0','0','0',
2639 '0','0','0','0','0','0','0','0',0};
2641 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2644 RegCloseKey(hkey2);
2646 /* UI stuff */
2647 uirow = MSI_CreateRecord(3);
2648 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2649 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2650 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2651 ui_actiondata(package,szProcessComponents,uirow);
2652 msiobj_release( &uirow->hdr );
2655 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2657 DWORD res;
2659 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2660 if (rc != ERROR_SUCCESS)
2661 continue;
2663 RegDeleteValueW(hkey2,squished_pc);
2665 /* if the key is empty delete it */
2666 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2667 RegCloseKey(hkey2);
2668 if (res == ERROR_NO_MORE_ITEMS)
2669 RegDeleteKeyW(hkey,squished_cc);
2671 /* UI stuff */
2672 uirow = MSI_CreateRecord(2);
2673 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2674 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2675 ui_actiondata(package,szProcessComponents,uirow);
2676 msiobj_release( &uirow->hdr );
2680 end:
2681 RegCloseKey(hkey);
2682 return rc;
2685 typedef struct {
2686 CLSID clsid;
2687 LPWSTR source;
2689 LPWSTR path;
2690 ITypeLib *ptLib;
2691 } typelib_struct;
2693 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2694 LPWSTR lpszName, LONG_PTR lParam)
2696 TLIBATTR *attr;
2697 typelib_struct *tl_struct = (typelib_struct*) lParam;
2698 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2699 int sz;
2700 HRESULT res;
2702 if (!IS_INTRESOURCE(lpszName))
2704 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2705 return TRUE;
2708 sz = strlenW(tl_struct->source)+4;
2709 sz *= sizeof(WCHAR);
2711 if ((INT)lpszName == 1)
2712 tl_struct->path = strdupW(tl_struct->source);
2713 else
2715 tl_struct->path = msi_alloc(sz);
2716 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2719 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2720 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2721 if (!SUCCEEDED(res))
2723 msi_free(tl_struct->path);
2724 tl_struct->path = NULL;
2726 return TRUE;
2729 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2730 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2732 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2733 return FALSE;
2736 msi_free(tl_struct->path);
2737 tl_struct->path = NULL;
2739 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2740 ITypeLib_Release(tl_struct->ptLib);
2742 return TRUE;
2745 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2747 MSIPACKAGE* package = (MSIPACKAGE*)param;
2748 LPCWSTR component;
2749 MSICOMPONENT *comp;
2750 MSIFILE *file;
2751 typelib_struct tl_struct;
2752 HMODULE module;
2753 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2755 component = MSI_RecordGetString(row,3);
2756 comp = get_loaded_component(package,component);
2757 if (!comp)
2758 return ERROR_SUCCESS;
2760 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2762 TRACE("Skipping typelib reg due to disabled component\n");
2764 comp->Action = comp->Installed;
2766 return ERROR_SUCCESS;
2769 comp->Action = INSTALLSTATE_LOCAL;
2771 file = get_loaded_file( package, comp->KeyPath );
2772 if (!file)
2773 return ERROR_SUCCESS;
2775 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2776 if (module)
2778 LPCWSTR guid;
2779 guid = MSI_RecordGetString(row,1);
2780 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2781 tl_struct.source = strdupW( file->TargetPath );
2782 tl_struct.path = NULL;
2784 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2785 (LONG_PTR)&tl_struct);
2787 if (tl_struct.path)
2789 LPWSTR help = NULL;
2790 LPCWSTR helpid;
2791 HRESULT res;
2793 helpid = MSI_RecordGetString(row,6);
2795 if (helpid)
2796 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2797 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2798 msi_free(help);
2800 if (!SUCCEEDED(res))
2801 ERR("Failed to register type library %s\n",
2802 debugstr_w(tl_struct.path));
2803 else
2805 ui_actiondata(package,szRegisterTypeLibraries,row);
2807 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2810 ITypeLib_Release(tl_struct.ptLib);
2811 msi_free(tl_struct.path);
2813 else
2814 ERR("Failed to load type library %s\n",
2815 debugstr_w(tl_struct.source));
2817 FreeLibrary(module);
2818 msi_free(tl_struct.source);
2820 else
2821 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2823 return ERROR_SUCCESS;
2826 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2829 * OK this is a bit confusing.. I am given a _Component key and I believe
2830 * that the file that is being registered as a type library is the "key file
2831 * of that component" which I interpret to mean "The file in the KeyPath of
2832 * that component".
2834 UINT rc;
2835 MSIQUERY * view;
2836 static const WCHAR Query[] =
2837 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2838 '`','T','y','p','e','L','i','b','`',0};
2840 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2841 if (rc != ERROR_SUCCESS)
2842 return ERROR_SUCCESS;
2844 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2845 msiobj_release(&view->hdr);
2846 return rc;
2849 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2851 MSIPACKAGE *package = (MSIPACKAGE*)param;
2852 LPWSTR target_file, target_folder;
2853 LPCWSTR buffer;
2854 WCHAR filename[0x100];
2855 DWORD sz;
2856 MSICOMPONENT *comp;
2857 static const WCHAR szlnk[]={'.','l','n','k',0};
2858 IShellLinkW *sl;
2859 IPersistFile *pf;
2860 HRESULT res;
2862 buffer = MSI_RecordGetString(row,4);
2863 comp = get_loaded_component(package,buffer);
2864 if (!comp)
2865 return ERROR_SUCCESS;
2867 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2869 TRACE("Skipping shortcut creation due to disabled component\n");
2871 comp->Action = comp->Installed;
2873 return ERROR_SUCCESS;
2876 comp->Action = INSTALLSTATE_LOCAL;
2878 ui_actiondata(package,szCreateShortcuts,row);
2880 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2881 &IID_IShellLinkW, (LPVOID *) &sl );
2883 if (FAILED(res))
2885 ERR("Is IID_IShellLink\n");
2886 return ERROR_SUCCESS;
2889 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2890 if( FAILED( res ) )
2892 ERR("Is IID_IPersistFile\n");
2893 return ERROR_SUCCESS;
2896 buffer = MSI_RecordGetString(row,2);
2897 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2899 /* may be needed because of a bug somehwere else */
2900 create_full_pathW(target_folder);
2902 sz = 0x100;
2903 MSI_RecordGetStringW(row,3,filename,&sz);
2904 reduce_to_longfilename(filename);
2905 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2906 strcatW(filename,szlnk);
2907 target_file = build_directory_name(2, target_folder, filename);
2908 msi_free(target_folder);
2910 buffer = MSI_RecordGetString(row,5);
2911 if (strchrW(buffer,'['))
2913 LPWSTR deformated;
2914 deformat_string(package,buffer,&deformated);
2915 IShellLinkW_SetPath(sl,deformated);
2916 msi_free(deformated);
2918 else
2920 FIXME("poorly handled shortcut format, advertised shortcut\n");
2921 IShellLinkW_SetPath(sl,comp->FullKeypath);
2924 if (!MSI_RecordIsNull(row,6))
2926 LPWSTR deformated;
2927 buffer = MSI_RecordGetString(row,6);
2928 deformat_string(package,buffer,&deformated);
2929 IShellLinkW_SetArguments(sl,deformated);
2930 msi_free(deformated);
2933 if (!MSI_RecordIsNull(row,7))
2935 buffer = MSI_RecordGetString(row,7);
2936 IShellLinkW_SetDescription(sl,buffer);
2939 if (!MSI_RecordIsNull(row,8))
2940 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2942 if (!MSI_RecordIsNull(row,9))
2944 LPWSTR Path;
2945 INT index;
2947 buffer = MSI_RecordGetString(row,9);
2949 Path = build_icon_path(package,buffer);
2950 index = MSI_RecordGetInteger(row,10);
2952 IShellLinkW_SetIconLocation(sl,Path,index);
2953 msi_free(Path);
2956 if (!MSI_RecordIsNull(row,11))
2957 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2959 if (!MSI_RecordIsNull(row,12))
2961 LPWSTR Path;
2962 buffer = MSI_RecordGetString(row,12);
2963 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2964 IShellLinkW_SetWorkingDirectory(sl,Path);
2965 msi_free(Path);
2968 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2969 IPersistFile_Save(pf,target_file,FALSE);
2971 msi_free(target_file);
2973 IPersistFile_Release( pf );
2974 IShellLinkW_Release( sl );
2976 return ERROR_SUCCESS;
2979 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2981 UINT rc;
2982 HRESULT res;
2983 MSIQUERY * view;
2984 static const WCHAR Query[] =
2985 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2986 '`','S','h','o','r','t','c','u','t','`',0};
2988 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2989 if (rc != ERROR_SUCCESS)
2990 return ERROR_SUCCESS;
2992 res = CoInitialize( NULL );
2993 if (FAILED (res))
2995 ERR("CoInitialize failed\n");
2996 return ERROR_FUNCTION_FAILED;
2999 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3000 msiobj_release(&view->hdr);
3002 CoUninitialize();
3004 return rc;
3007 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3009 MSIPACKAGE* package = (MSIPACKAGE*)param;
3010 HANDLE the_file;
3011 LPWSTR FilePath;
3012 LPCWSTR FileName;
3013 CHAR buffer[1024];
3014 DWORD sz;
3015 UINT rc;
3017 FileName = MSI_RecordGetString(row,1);
3018 if (!FileName)
3020 ERR("Unable to get FileName\n");
3021 return ERROR_SUCCESS;
3024 FilePath = build_icon_path(package,FileName);
3026 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3028 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3029 FILE_ATTRIBUTE_NORMAL, NULL);
3031 if (the_file == INVALID_HANDLE_VALUE)
3033 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3034 msi_free(FilePath);
3035 return ERROR_SUCCESS;
3040 DWORD write;
3041 sz = 1024;
3042 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3043 if (rc != ERROR_SUCCESS)
3045 ERR("Failed to get stream\n");
3046 CloseHandle(the_file);
3047 DeleteFileW(FilePath);
3048 break;
3050 WriteFile(the_file,buffer,sz,&write,NULL);
3051 } while (sz == 1024);
3053 msi_free(FilePath);
3055 CloseHandle(the_file);
3056 return ERROR_SUCCESS;
3060 * 99% of the work done here is only done for
3061 * advertised installs. However this is where the
3062 * Icon table is processed and written out
3063 * so that is what I am going to do here.
3065 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3067 UINT rc;
3068 MSIQUERY * view;
3069 static const WCHAR Query[]=
3070 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3071 '`','I','c','o','n','`',0};
3072 /* for registry stuff */
3073 HKEY hkey=0;
3074 HKEY hukey=0;
3075 static const WCHAR szProductLanguage[] =
3076 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3077 static const WCHAR szARPProductIcon[] =
3078 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3079 static const WCHAR szProductVersion[] =
3080 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3081 DWORD langid;
3082 LPWSTR buffer;
3083 DWORD size;
3084 MSIHANDLE hDb, hSumInfo;
3086 /* write out icon files */
3088 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3089 if (rc == ERROR_SUCCESS)
3091 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3092 msiobj_release(&view->hdr);
3095 /* ok there is a lot more done here but i need to figure out what */
3097 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3098 if (rc != ERROR_SUCCESS)
3099 goto end;
3101 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3102 if (rc != ERROR_SUCCESS)
3103 goto end;
3106 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3107 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3108 msi_free(buffer);
3110 langid = msi_get_property_int( package, szProductLanguage, 0 );
3111 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3113 buffer = msi_dup_property( package, szARPProductIcon );
3114 if (buffer)
3116 LPWSTR path = build_icon_path(package,buffer);
3117 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3118 msi_free( path );
3120 msi_free(buffer);
3122 buffer = msi_dup_property( package, szProductVersion );
3123 if (buffer)
3125 DWORD verdword = build_version_dword(buffer);
3126 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3128 msi_free(buffer);
3130 /* FIXME: Need to write more keys to the user registry */
3132 hDb= alloc_msihandle( &package->db->hdr );
3133 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3134 MsiCloseHandle(hDb);
3135 if (rc == ERROR_SUCCESS)
3137 WCHAR guidbuffer[0x200];
3138 size = 0x200;
3139 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3140 guidbuffer, &size);
3141 if (rc == ERROR_SUCCESS)
3143 WCHAR squashed[GUID_SIZE];
3144 /* for now we only care about the first guid */
3145 LPWSTR ptr = strchrW(guidbuffer,';');
3146 if (ptr) *ptr = 0;
3147 squash_guid(guidbuffer,squashed);
3148 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3150 else
3152 ERR("Unable to query Revision_Number...\n");
3153 rc = ERROR_SUCCESS;
3155 MsiCloseHandle(hSumInfo);
3157 else
3159 ERR("Unable to open Summary Information\n");
3160 rc = ERROR_SUCCESS;
3163 end:
3165 RegCloseKey(hkey);
3166 RegCloseKey(hukey);
3168 return rc;
3171 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3173 MSIPACKAGE *package = (MSIPACKAGE*)param;
3174 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3175 LPWSTR deformated_section, deformated_key, deformated_value;
3176 LPWSTR folder, fullname = NULL;
3177 MSIRECORD * uirow;
3178 INT action;
3179 MSICOMPONENT *comp;
3180 static const WCHAR szWindowsFolder[] =
3181 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3183 component = MSI_RecordGetString(row, 8);
3184 comp = get_loaded_component(package,component);
3186 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3188 TRACE("Skipping ini file due to disabled component %s\n",
3189 debugstr_w(component));
3191 comp->Action = comp->Installed;
3193 return ERROR_SUCCESS;
3196 comp->Action = INSTALLSTATE_LOCAL;
3198 identifier = MSI_RecordGetString(row,1);
3199 filename = MSI_RecordGetString(row,2);
3200 dirproperty = MSI_RecordGetString(row,3);
3201 section = MSI_RecordGetString(row,4);
3202 key = MSI_RecordGetString(row,5);
3203 value = MSI_RecordGetString(row,6);
3204 action = MSI_RecordGetInteger(row,7);
3206 deformat_string(package,section,&deformated_section);
3207 deformat_string(package,key,&deformated_key);
3208 deformat_string(package,value,&deformated_value);
3210 if (dirproperty)
3212 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3213 if (!folder)
3214 folder = msi_dup_property( package, dirproperty );
3216 else
3217 folder = msi_dup_property( package, szWindowsFolder );
3219 if (!folder)
3221 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3222 goto cleanup;
3225 fullname = build_directory_name(2, folder, filename);
3227 if (action == 0)
3229 TRACE("Adding value %s to section %s in %s\n",
3230 debugstr_w(deformated_key), debugstr_w(deformated_section),
3231 debugstr_w(fullname));
3232 WritePrivateProfileStringW(deformated_section, deformated_key,
3233 deformated_value, fullname);
3235 else if (action == 1)
3237 WCHAR returned[10];
3238 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3239 returned, 10, fullname);
3240 if (returned[0] == 0)
3242 TRACE("Adding value %s to section %s in %s\n",
3243 debugstr_w(deformated_key), debugstr_w(deformated_section),
3244 debugstr_w(fullname));
3246 WritePrivateProfileStringW(deformated_section, deformated_key,
3247 deformated_value, fullname);
3250 else if (action == 3)
3251 FIXME("Append to existing section not yet implemented\n");
3253 uirow = MSI_CreateRecord(4);
3254 MSI_RecordSetStringW(uirow,1,identifier);
3255 MSI_RecordSetStringW(uirow,2,deformated_section);
3256 MSI_RecordSetStringW(uirow,3,deformated_key);
3257 MSI_RecordSetStringW(uirow,4,deformated_value);
3258 ui_actiondata(package,szWriteIniValues,uirow);
3259 msiobj_release( &uirow->hdr );
3260 cleanup:
3261 msi_free(fullname);
3262 msi_free(folder);
3263 msi_free(deformated_key);
3264 msi_free(deformated_value);
3265 msi_free(deformated_section);
3266 return ERROR_SUCCESS;
3269 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3271 UINT rc;
3272 MSIQUERY * view;
3273 static const WCHAR ExecSeqQuery[] =
3274 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3275 '`','I','n','i','F','i','l','e','`',0};
3277 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3278 if (rc != ERROR_SUCCESS)
3280 TRACE("no IniFile table\n");
3281 return ERROR_SUCCESS;
3284 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3285 msiobj_release(&view->hdr);
3286 return rc;
3289 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3291 MSIPACKAGE *package = (MSIPACKAGE*)param;
3292 LPCWSTR filename;
3293 LPWSTR FullName;
3294 MSIFILE *file;
3295 DWORD len;
3296 static const WCHAR ExeStr[] =
3297 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3298 static const WCHAR close[] = {'\"',0};
3299 STARTUPINFOW si;
3300 PROCESS_INFORMATION info;
3301 BOOL brc;
3303 memset(&si,0,sizeof(STARTUPINFOW));
3305 filename = MSI_RecordGetString(row,1);
3306 file = get_loaded_file( package, filename );
3308 if (!file)
3310 ERR("Unable to find file id %s\n",debugstr_w(filename));
3311 return ERROR_SUCCESS;
3314 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3316 FullName = msi_alloc(len*sizeof(WCHAR));
3317 strcpyW(FullName,ExeStr);
3318 strcatW( FullName, file->TargetPath );
3319 strcatW(FullName,close);
3321 TRACE("Registering %s\n",debugstr_w(FullName));
3322 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3323 &si, &info);
3325 if (brc)
3326 msi_dialog_check_messages(info.hProcess);
3328 msi_free(FullName);
3329 return ERROR_SUCCESS;
3332 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3334 UINT rc;
3335 MSIQUERY * view;
3336 static const WCHAR ExecSeqQuery[] =
3337 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3338 '`','S','e','l','f','R','e','g','`',0};
3340 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3341 if (rc != ERROR_SUCCESS)
3343 TRACE("no SelfReg table\n");
3344 return ERROR_SUCCESS;
3347 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3348 msiobj_release(&view->hdr);
3350 return ERROR_SUCCESS;
3353 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3355 MSIFEATURE *feature;
3356 UINT rc;
3357 HKEY hkey=0;
3358 HKEY hukey=0;
3360 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3361 if (rc != ERROR_SUCCESS)
3362 goto end;
3364 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3365 if (rc != ERROR_SUCCESS)
3366 goto end;
3368 /* here the guids are base 85 encoded */
3369 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3371 ComponentList *cl;
3372 LPWSTR data = NULL;
3373 GUID clsid;
3374 INT size;
3375 BOOL absent = FALSE;
3377 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3378 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3379 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3380 absent = TRUE;
3382 size = 1;
3383 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3385 size += 21;
3387 if (feature->Feature_Parent)
3388 size += strlenW( feature->Feature_Parent )+2;
3390 data = msi_alloc(size * sizeof(WCHAR));
3392 data[0] = 0;
3393 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3395 MSICOMPONENT* component = cl->component;
3396 WCHAR buf[21];
3398 memset(buf,0,sizeof(buf));
3399 if (component->ComponentId)
3401 TRACE("From %s\n",debugstr_w(component->ComponentId));
3402 CLSIDFromString(component->ComponentId, &clsid);
3403 encode_base85_guid(&clsid,buf);
3404 TRACE("to %s\n",debugstr_w(buf));
3405 strcatW(data,buf);
3408 if (feature->Feature_Parent)
3410 static const WCHAR sep[] = {'\2',0};
3411 strcatW(data,sep);
3412 strcatW(data,feature->Feature_Parent);
3415 msi_reg_set_val_str( hkey, feature->Feature, data );
3416 msi_free(data);
3418 size = 0;
3419 if (feature->Feature_Parent)
3420 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3421 if (!absent)
3423 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3424 (LPBYTE)feature->Feature_Parent,size);
3426 else
3428 size += 2*sizeof(WCHAR);
3429 data = msi_alloc(size);
3430 data[0] = 0x6;
3431 data[1] = 0;
3432 if (feature->Feature_Parent)
3433 strcpyW( &data[1], feature->Feature_Parent );
3434 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3435 (LPBYTE)data,size);
3436 msi_free(data);
3440 end:
3441 RegCloseKey(hkey);
3442 RegCloseKey(hukey);
3443 return rc;
3446 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3448 static const WCHAR installerPathFmt[] = {
3449 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3450 static const WCHAR fmt[] = {
3451 '%','s','\\',
3452 'I','n','s','t','a','l','l','e','r','\\',
3453 '%','x','.','m','s','i',0};
3454 static const WCHAR szOriginalDatabase[] =
3455 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3456 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3457 INT num, start;
3458 LPWSTR msiFilePath;
3459 BOOL r;
3461 /* copy the package locally */
3462 num = GetTickCount() & 0xffff;
3463 if (!num)
3464 num = 1;
3465 start = num;
3466 GetWindowsDirectoryW( windir, MAX_PATH );
3467 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3470 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3471 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3472 if (handle != INVALID_HANDLE_VALUE)
3474 CloseHandle(handle);
3475 break;
3477 if (GetLastError() != ERROR_FILE_EXISTS &&
3478 GetLastError() != ERROR_SHARING_VIOLATION)
3479 break;
3480 if (!(++num & 0xffff)) num = 1;
3481 sprintfW(packagefile,fmt,num);
3482 } while (num != start);
3484 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3485 create_full_pathW(path);
3487 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3489 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3490 r = CopyFileW( msiFilePath, packagefile, FALSE);
3491 msi_free( msiFilePath );
3493 if (!r)
3495 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3496 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3497 return ERROR_FUNCTION_FAILED;
3500 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3501 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3502 return ERROR_SUCCESS;
3505 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3507 LPWSTR prop, val, key;
3508 static const LPCSTR propval[] = {
3509 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3510 "ARPCONTACT", "Contact",
3511 "ARPCOMMENTS", "Comments",
3512 "ProductName", "DisplayName",
3513 "ProductVersion", "DisplayVersion",
3514 "ARPHELPLINK", "HelpLink",
3515 "ARPHELPTELEPHONE", "HelpTelephone",
3516 "ARPINSTALLLOCATION", "InstallLocation",
3517 "SourceDir", "InstallSource",
3518 "Manufacturer", "Publisher",
3519 "ARPREADME", "Readme",
3520 "ARPSIZE", "Size",
3521 "ARPURLINFOABOUT", "URLInfoAbout",
3522 "ARPURLUPDATEINFO", "URLUpdateInfo",
3523 NULL,
3525 const LPCSTR *p = propval;
3527 while( *p )
3529 prop = strdupAtoW( *p++ );
3530 key = strdupAtoW( *p++ );
3531 val = msi_dup_property( package, prop );
3532 msi_reg_set_val_str( hkey, key, val );
3533 msi_free(val);
3534 msi_free(key);
3535 msi_free(prop);
3537 return ERROR_SUCCESS;
3540 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3542 HKEY hkey=0;
3543 LPWSTR buffer = NULL;
3544 UINT rc;
3545 DWORD size, langid;
3546 static const WCHAR szWindowsInstaller[] =
3547 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3548 static const WCHAR szUpgradeCode[] =
3549 {'U','p','g','r','a','d','e','C','o','d','e',0};
3550 static const WCHAR modpath_fmt[] =
3551 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3552 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3553 static const WCHAR szModifyPath[] =
3554 {'M','o','d','i','f','y','P','a','t','h',0};
3555 static const WCHAR szUninstallString[] =
3556 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3557 static const WCHAR szEstimatedSize[] =
3558 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3559 static const WCHAR szProductLanguage[] =
3560 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3561 static const WCHAR szProductVersion[] =
3562 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3564 SYSTEMTIME systime;
3565 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3566 LPWSTR upgrade_code;
3567 WCHAR szDate[9];
3569 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3570 if (rc != ERROR_SUCCESS)
3571 return rc;
3573 /* dump all the info i can grab */
3574 /* FIXME: Flesh out more information */
3576 msi_write_uninstall_property_vals( package, hkey );
3578 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3580 msi_make_package_local( package, hkey );
3582 /* do ModifyPath and UninstallString */
3583 size = deformat_string(package,modpath_fmt,&buffer);
3584 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3585 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3586 msi_free(buffer);
3588 /* FIXME: Write real Estimated Size when we have it */
3589 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3591 GetLocalTime(&systime);
3592 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3593 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3595 langid = msi_get_property_int( package, szProductLanguage, 0 );
3596 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3598 buffer = msi_dup_property( package, szProductVersion );
3599 if (buffer)
3601 DWORD verdword = build_version_dword(buffer);
3603 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3604 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3605 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3607 msi_free(buffer);
3609 /* Handle Upgrade Codes */
3610 upgrade_code = msi_dup_property( package, szUpgradeCode );
3611 if (upgrade_code)
3613 HKEY hkey2;
3614 WCHAR squashed[33];
3615 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3616 squash_guid(package->ProductCode,squashed);
3617 msi_reg_set_val_str( hkey2, squashed, NULL );
3618 RegCloseKey(hkey2);
3619 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3620 squash_guid(package->ProductCode,squashed);
3621 msi_reg_set_val_str( hkey2, squashed, NULL );
3622 RegCloseKey(hkey2);
3624 msi_free(upgrade_code);
3627 RegCloseKey(hkey);
3629 return ERROR_SUCCESS;
3632 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3634 return execute_script(package,INSTALL_SCRIPT);
3637 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3639 UINT rc;
3641 /* turn off scheduleing */
3642 package->script->CurrentlyScripting= FALSE;
3644 /* first do the same as an InstallExecute */
3645 rc = ACTION_InstallExecute(package);
3646 if (rc != ERROR_SUCCESS)
3647 return rc;
3649 /* then handle Commit Actions */
3650 rc = execute_script(package,COMMIT_SCRIPT);
3652 return rc;
3655 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3657 static const WCHAR RunOnce[] = {
3658 'S','o','f','t','w','a','r','e','\\',
3659 'M','i','c','r','o','s','o','f','t','\\',
3660 'W','i','n','d','o','w','s','\\',
3661 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3662 'R','u','n','O','n','c','e',0};
3663 static const WCHAR InstallRunOnce[] = {
3664 'S','o','f','t','w','a','r','e','\\',
3665 'M','i','c','r','o','s','o','f','t','\\',
3666 'W','i','n','d','o','w','s','\\',
3667 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3668 'I','n','s','t','a','l','l','e','r','\\',
3669 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3671 static const WCHAR msiexec_fmt[] = {
3672 '%','s',
3673 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3674 '\"','%','s','\"',0};
3675 static const WCHAR install_fmt[] = {
3676 '/','I',' ','\"','%','s','\"',' ',
3677 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3678 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3679 WCHAR buffer[256], sysdir[MAX_PATH];
3680 HKEY hkey;
3681 WCHAR squished_pc[100];
3683 squash_guid(package->ProductCode,squished_pc);
3685 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3686 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3687 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3688 squished_pc);
3690 msi_reg_set_val_str( hkey, squished_pc, buffer );
3691 RegCloseKey(hkey);
3693 TRACE("Reboot command %s\n",debugstr_w(buffer));
3695 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3696 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3698 msi_reg_set_val_str( hkey, squished_pc, buffer );
3699 RegCloseKey(hkey);
3701 return ERROR_INSTALL_SUSPEND;
3704 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3706 DWORD attrib;
3707 UINT rc;
3709 * we are currently doing what should be done here in the top level Install
3710 * however for Adminastrative and uninstalls this step will be needed
3712 if (!package->PackagePath)
3713 return ERROR_SUCCESS;
3715 attrib = GetFileAttributesW(package->PackagePath);
3716 if (attrib == INVALID_FILE_ATTRIBUTES)
3718 LPWSTR prompt;
3719 LPWSTR msg;
3720 DWORD size = 0;
3722 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3723 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3724 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3725 if (rc == ERROR_MORE_DATA)
3727 prompt = msi_alloc(size * sizeof(WCHAR));
3728 MsiSourceListGetInfoW(package->ProductCode, NULL,
3729 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3730 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3732 else
3733 prompt = strdupW(package->PackagePath);
3735 msg = generate_error_string(package,1302,1,prompt);
3736 while(attrib == INVALID_FILE_ATTRIBUTES)
3738 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3739 if (rc == IDCANCEL)
3741 rc = ERROR_INSTALL_USEREXIT;
3742 break;
3744 attrib = GetFileAttributesW(package->PackagePath);
3746 msi_free(prompt);
3747 rc = ERROR_SUCCESS;
3749 else
3750 return ERROR_SUCCESS;
3752 return rc;
3755 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3757 HKEY hkey=0;
3758 LPWSTR buffer;
3759 LPWSTR productid;
3760 UINT rc,i;
3762 static const WCHAR szPropKeys[][80] =
3764 {'P','r','o','d','u','c','t','I','D',0},
3765 {'U','S','E','R','N','A','M','E',0},
3766 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3767 {0},
3770 static const WCHAR szRegKeys[][80] =
3772 {'P','r','o','d','u','c','t','I','D',0},
3773 {'R','e','g','O','w','n','e','r',0},
3774 {'R','e','g','C','o','m','p','a','n','y',0},
3775 {0},
3778 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3779 if (!productid)
3780 return ERROR_SUCCESS;
3782 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3783 if (rc != ERROR_SUCCESS)
3784 goto end;
3786 for( i = 0; szPropKeys[i][0]; i++ )
3788 buffer = msi_dup_property( package, szPropKeys[i] );
3789 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3790 msi_free( buffer );
3793 end:
3794 msi_free(productid);
3795 RegCloseKey(hkey);
3797 return ERROR_SUCCESS;
3801 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3803 UINT rc;
3805 package->script->InWhatSequence |= SEQUENCE_EXEC;
3806 rc = ACTION_ProcessExecSequence(package,FALSE);
3807 return rc;
3812 * Code based off of code located here
3813 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3815 * Using string index 4 (full font name) instead of 1 (family name)
3817 static LPWSTR load_ttfname_from(LPCWSTR filename)
3819 HANDLE handle;
3820 LPWSTR ret = NULL;
3821 int i;
3823 typedef struct _tagTT_OFFSET_TABLE{
3824 USHORT uMajorVersion;
3825 USHORT uMinorVersion;
3826 USHORT uNumOfTables;
3827 USHORT uSearchRange;
3828 USHORT uEntrySelector;
3829 USHORT uRangeShift;
3830 }TT_OFFSET_TABLE;
3832 typedef struct _tagTT_TABLE_DIRECTORY{
3833 char szTag[4]; /* table name */
3834 ULONG uCheckSum; /* Check sum */
3835 ULONG uOffset; /* Offset from beginning of file */
3836 ULONG uLength; /* length of the table in bytes */
3837 }TT_TABLE_DIRECTORY;
3839 typedef struct _tagTT_NAME_TABLE_HEADER{
3840 USHORT uFSelector; /* format selector. Always 0 */
3841 USHORT uNRCount; /* Name Records count */
3842 USHORT uStorageOffset; /* Offset for strings storage,
3843 * from start of the table */
3844 }TT_NAME_TABLE_HEADER;
3846 typedef struct _tagTT_NAME_RECORD{
3847 USHORT uPlatformID;
3848 USHORT uEncodingID;
3849 USHORT uLanguageID;
3850 USHORT uNameID;
3851 USHORT uStringLength;
3852 USHORT uStringOffset; /* from start of storage area */
3853 }TT_NAME_RECORD;
3855 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3856 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3858 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3859 FILE_ATTRIBUTE_NORMAL, 0 );
3860 if (handle != INVALID_HANDLE_VALUE)
3862 TT_TABLE_DIRECTORY tblDir;
3863 BOOL bFound = FALSE;
3864 TT_OFFSET_TABLE ttOffsetTable;
3865 DWORD dwRead;
3867 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3868 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3869 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3870 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3872 if (ttOffsetTable.uMajorVersion != 1 ||
3873 ttOffsetTable.uMinorVersion != 0)
3874 return NULL;
3876 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3878 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3879 if (strncmp(tblDir.szTag,"name",4)==0)
3881 bFound = TRUE;
3882 tblDir.uLength = SWAPLONG(tblDir.uLength);
3883 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3884 break;
3888 if (bFound)
3890 TT_NAME_TABLE_HEADER ttNTHeader;
3891 TT_NAME_RECORD ttRecord;
3893 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3894 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3895 &dwRead,NULL);
3897 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3898 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3899 bFound = FALSE;
3900 for(i=0; i<ttNTHeader.uNRCount; i++)
3902 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3903 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3904 /* 4 is the Full Font Name */
3905 if(ttRecord.uNameID == 4)
3907 int nPos;
3908 LPSTR buf;
3909 static LPCSTR tt = " (TrueType)";
3911 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3912 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3913 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3914 SetFilePointer(handle, tblDir.uOffset +
3915 ttRecord.uStringOffset +
3916 ttNTHeader.uStorageOffset,
3917 NULL, FILE_BEGIN);
3918 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3919 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3920 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3921 if (strlen(buf) > 0)
3923 strcat(buf,tt);
3924 ret = strdupAtoW(buf);
3925 msi_free(buf);
3926 break;
3929 msi_free(buf);
3930 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3934 CloseHandle(handle);
3936 else
3937 ERR("Unable to open font file %s\n", debugstr_w(filename));
3939 TRACE("Returning fontname %s\n",debugstr_w(ret));
3940 return ret;
3943 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3945 MSIPACKAGE *package = (MSIPACKAGE*)param;
3946 LPWSTR name;
3947 LPCWSTR filename;
3948 MSIFILE *file;
3949 static const WCHAR regfont1[] =
3950 {'S','o','f','t','w','a','r','e','\\',
3951 'M','i','c','r','o','s','o','f','t','\\',
3952 'W','i','n','d','o','w','s',' ','N','T','\\',
3953 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3954 'F','o','n','t','s',0};
3955 static const WCHAR regfont2[] =
3956 {'S','o','f','t','w','a','r','e','\\',
3957 'M','i','c','r','o','s','o','f','t','\\',
3958 'W','i','n','d','o','w','s','\\',
3959 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3960 'F','o','n','t','s',0};
3961 HKEY hkey1;
3962 HKEY hkey2;
3964 filename = MSI_RecordGetString( row, 1 );
3965 file = get_loaded_file( package, filename );
3966 if (!file)
3968 ERR("Unable to load file\n");
3969 return ERROR_SUCCESS;
3972 /* check to make sure that component is installed */
3973 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3975 TRACE("Skipping: Component not scheduled for install\n");
3976 return ERROR_SUCCESS;
3979 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3980 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3982 if (MSI_RecordIsNull(row,2))
3983 name = load_ttfname_from( file->TargetPath );
3984 else
3985 name = msi_dup_record_field(row,2);
3987 if (name)
3989 msi_reg_set_val_str( hkey1, name, file->FileName );
3990 msi_reg_set_val_str( hkey2, name, file->FileName );
3993 msi_free(name);
3994 RegCloseKey(hkey1);
3995 RegCloseKey(hkey2);
3996 return ERROR_SUCCESS;
3999 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4001 UINT rc;
4002 MSIQUERY * view;
4003 static const WCHAR ExecSeqQuery[] =
4004 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4005 '`','F','o','n','t','`',0};
4007 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4008 if (rc != ERROR_SUCCESS)
4010 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4011 return ERROR_SUCCESS;
4014 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4015 msiobj_release(&view->hdr);
4017 return ERROR_SUCCESS;
4020 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4022 MSIPACKAGE *package = (MSIPACKAGE*)param;
4023 LPCWSTR compgroupid=NULL;
4024 LPCWSTR feature=NULL;
4025 LPCWSTR text = NULL;
4026 LPCWSTR qualifier = NULL;
4027 LPCWSTR component = NULL;
4028 LPWSTR advertise = NULL;
4029 LPWSTR output = NULL;
4030 HKEY hkey;
4031 UINT rc = ERROR_SUCCESS;
4032 MSICOMPONENT *comp;
4033 DWORD sz = 0;
4035 component = MSI_RecordGetString(rec,3);
4036 comp = get_loaded_component(package,component);
4038 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4039 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4040 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4042 TRACE("Skipping: Component %s not scheduled for install\n",
4043 debugstr_w(component));
4045 return ERROR_SUCCESS;
4048 compgroupid = MSI_RecordGetString(rec,1);
4050 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4051 if (rc != ERROR_SUCCESS)
4052 goto end;
4054 text = MSI_RecordGetString(rec,4);
4055 qualifier = MSI_RecordGetString(rec,2);
4056 feature = MSI_RecordGetString(rec,5);
4058 advertise = create_component_advertise_string(package, comp, feature);
4060 sz = strlenW(advertise);
4062 if (text)
4063 sz += lstrlenW(text);
4065 sz+=3;
4066 sz *= sizeof(WCHAR);
4068 output = msi_alloc(sz);
4069 memset(output,0,sz);
4070 strcpyW(output,advertise);
4071 msi_free(advertise);
4073 if (text)
4074 strcatW(output,text);
4076 msi_reg_set_val_multi_str( hkey, qualifier, output );
4078 end:
4079 RegCloseKey(hkey);
4080 msi_free(output);
4082 return rc;
4086 * At present I am ignorning the advertised components part of this and only
4087 * focusing on the qualified component sets
4089 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4091 UINT rc;
4092 MSIQUERY * view;
4093 static const WCHAR ExecSeqQuery[] =
4094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4095 '`','P','u','b','l','i','s','h',
4096 'C','o','m','p','o','n','e','n','t','`',0};
4098 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4099 if (rc != ERROR_SUCCESS)
4100 return ERROR_SUCCESS;
4102 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4103 msiobj_release(&view->hdr);
4105 return rc;
4108 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4109 LPCSTR action, LPCWSTR table )
4111 static const WCHAR query[] = {
4112 'S','E','L','E','C','T',' ','*',' ',
4113 'F','R','O','M',' ','`','%','s','`',0 };
4114 MSIQUERY *view = NULL;
4115 DWORD count = 0;
4116 UINT r;
4118 r = MSI_OpenQuery( package->db, &view, query, table );
4119 if (r == ERROR_SUCCESS)
4121 r = MSI_IterateRecords(view, &count, NULL, package);
4122 msiobj_release(&view->hdr);
4125 if (count)
4126 FIXME("%s -> %lu ignored %s table values\n",
4127 action, count, debugstr_w(table));
4129 return ERROR_SUCCESS;
4132 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4134 TRACE("%p\n", package);
4135 return ERROR_SUCCESS;
4138 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4140 static const WCHAR table[] =
4141 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4142 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4145 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4147 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4148 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4151 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4153 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4154 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4157 static UINT ACTION_BindImage( MSIPACKAGE *package )
4159 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4160 return msi_unimplemented_action_stub( package, "BindImage", table );
4163 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4165 static const WCHAR table[] = {
4166 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4167 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4170 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4172 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4173 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4176 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4178 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4179 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4182 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4184 static const WCHAR table[] = {
4185 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4186 return msi_unimplemented_action_stub( package, "InstallServices", table );
4189 static UINT ACTION_StartServices( MSIPACKAGE *package )
4191 static const WCHAR table[] = {
4192 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4193 return msi_unimplemented_action_stub( package, "StartServices", table );
4196 static UINT ACTION_StopServices( MSIPACKAGE *package )
4198 static const WCHAR table[] = {
4199 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4200 return msi_unimplemented_action_stub( package, "StopServices", table );
4203 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4205 static const WCHAR table[] = {
4206 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4207 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4210 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4212 static const WCHAR table[] = {
4213 'E','n','v','i','r','o','n','m','e','n','t',0 };
4214 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4217 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4219 static const WCHAR table[] = {
4220 'E','n','v','i','r','o','n','m','e','n','t',0 };
4221 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4224 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4226 static const WCHAR table[] = {
4227 'M','s','i','A','s','s','e','m','b','l','y',0 };
4228 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4231 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4233 static const WCHAR table[] = {
4234 'M','s','i','A','s','s','e','m','b','l','y',0 };
4235 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4238 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4240 static const WCHAR table[] = { 'F','o','n','t',0 };
4241 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4244 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4246 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4247 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4250 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4252 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4253 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4256 static struct _actions StandardActions[] = {
4257 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4258 { szAppSearch, ACTION_AppSearch },
4259 { szBindImage, ACTION_BindImage },
4260 { szCCPSearch, ACTION_CCPSearch},
4261 { szCostFinalize, ACTION_CostFinalize },
4262 { szCostInitialize, ACTION_CostInitialize },
4263 { szCreateFolders, ACTION_CreateFolders },
4264 { szCreateShortcuts, ACTION_CreateShortcuts },
4265 { szDeleteServices, ACTION_DeleteServices },
4266 { szDisableRollback, NULL},
4267 { szDuplicateFiles, ACTION_DuplicateFiles },
4268 { szExecuteAction, ACTION_ExecuteAction },
4269 { szFileCost, ACTION_FileCost },
4270 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4271 { szForceReboot, ACTION_ForceReboot },
4272 { szInstallAdminPackage, NULL},
4273 { szInstallExecute, ACTION_InstallExecute },
4274 { szInstallExecuteAgain, ACTION_InstallExecute },
4275 { szInstallFiles, ACTION_InstallFiles},
4276 { szInstallFinalize, ACTION_InstallFinalize },
4277 { szInstallInitialize, ACTION_InstallInitialize },
4278 { szInstallSFPCatalogFile, NULL},
4279 { szInstallValidate, ACTION_InstallValidate },
4280 { szIsolateComponents, ACTION_IsolateComponents },
4281 { szLaunchConditions, ACTION_LaunchConditions },
4282 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4283 { szMoveFiles, ACTION_MoveFiles },
4284 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4285 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4286 { szInstallODBC, NULL},
4287 { szInstallServices, ACTION_InstallServices },
4288 { szPatchFiles, ACTION_PatchFiles },
4289 { szProcessComponents, ACTION_ProcessComponents },
4290 { szPublishComponents, ACTION_PublishComponents },
4291 { szPublishFeatures, ACTION_PublishFeatures },
4292 { szPublishProduct, ACTION_PublishProduct },
4293 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4294 { szRegisterComPlus, NULL},
4295 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4296 { szRegisterFonts, ACTION_RegisterFonts },
4297 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4298 { szRegisterProduct, ACTION_RegisterProduct },
4299 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4300 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4301 { szRegisterUser, ACTION_RegisterUser},
4302 { szRemoveDuplicateFiles, NULL},
4303 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4304 { szRemoveExistingProducts, NULL},
4305 { szRemoveFiles, ACTION_RemoveFiles},
4306 { szRemoveFolders, NULL},
4307 { szRemoveIniValues, ACTION_RemoveIniValues },
4308 { szRemoveODBC, NULL},
4309 { szRemoveRegistryValues, NULL},
4310 { szRemoveShortcuts, NULL},
4311 { szResolveSource, ACTION_ResolveSource},
4312 { szRMCCPSearch, ACTION_RMCCPSearch},
4313 { szScheduleReboot, NULL},
4314 { szSelfRegModules, ACTION_SelfRegModules },
4315 { szSelfUnregModules, ACTION_SelfUnregModules },
4316 { szSetODBCFolders, NULL},
4317 { szStartServices, ACTION_StartServices },
4318 { szStopServices, ACTION_StopServices },
4319 { szUnpublishComponents, NULL},
4320 { szUnpublishFeatures, NULL},
4321 { szUnregisterClassInfo, NULL},
4322 { szUnregisterComPlus, NULL},
4323 { szUnregisterExtensionInfo, NULL},
4324 { szUnregisterFonts, ACTION_UnregisterFonts },
4325 { szUnregisterMIMEInfo, NULL},
4326 { szUnregisterProgIdInfo, NULL},
4327 { szUnregisterTypeLibraries, NULL},
4328 { szValidateProductID, NULL},
4329 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4330 { szWriteIniValues, ACTION_WriteIniValues },
4331 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4332 { NULL, NULL},