Define MSIDBOPEN_ constants using LPCWSTR when compiling Wine.
[wine/multimedia.git] / dlls / msi / action.c
bloba26585bc528b3fa2899e9751881c1729f6a1d2d1
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
31 #define COBJMACROS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "wine/debug.h"
38 #include "msidefs.h"
39 #include "msipriv.h"
40 #include "winuser.h"
41 #include "shlobj.h"
42 #include "wine/unicode.h"
43 #include "winver.h"
44 #include "action.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 * Prototypes
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238 struct _actions {
239 LPCWSTR action;
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
247 * helper functions
248 ********************************************************/
250 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
252 static const WCHAR szActionText[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
254 MSIRECORD *row;
256 row = MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row,1,action);
258 ControlEvent_FireSubscribedEvent(package,szActionText, row);
259 msiobj_release(&row->hdr);
262 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
264 static const WCHAR template_s[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
266 '.',0};
267 static const WCHAR format[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
274 WCHAR message[1024];
275 WCHAR timet[0x100];
276 MSIRECORD * row = 0;
277 LPCWSTR ActionText;
278 LPWSTR deformated;
280 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
282 row = MSI_QueryGetRecord( package->db, Query_t, action );
283 if (!row)
284 return;
286 ActionText = MSI_RecordGetString(row,2);
287 deformat_string(package, ActionText, &deformated);
289 sprintfW(message,template_s,timet,action,deformated);
290 ce_actiontext(package, deformated);
291 msiobj_release(&row->hdr);
293 row = MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row,1,message);
296 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
297 msiobj_release(&row->hdr);
298 msi_free(deformated);
301 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
302 UINT rc)
304 MSIRECORD * row;
305 static const WCHAR template_s[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
307 '%','s', '.',0};
308 static const WCHAR template_e[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
311 '%','i','.',0};
312 static const WCHAR format[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
314 WCHAR message[1024];
315 WCHAR timet[0x100];
317 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
318 if (start)
319 sprintfW(message,template_s,timet,action);
320 else
321 sprintfW(message,template_e,timet,action,rc);
323 row = MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row,1,message);
326 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
327 msiobj_release(&row->hdr);
330 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
332 LPWSTR str = msi_dup_property( package, prop );
333 int val = str ? atoiW( str ) : def;
334 msi_free( str );
335 return val;
338 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
340 LPCWSTR ptr,ptr2;
341 BOOL quote;
342 DWORD len;
343 LPWSTR prop = NULL, val = NULL;
345 if (!szCommandLine)
346 return ERROR_SUCCESS;
348 ptr = szCommandLine;
350 while (*ptr)
352 if (*ptr==' ')
354 ptr++;
355 continue;
358 TRACE("Looking at %s\n",debugstr_w(ptr));
360 ptr2 = strchrW(ptr,'=');
361 if (!ptr2)
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
364 break;
367 quote = FALSE;
369 len = ptr2-ptr;
370 prop = msi_alloc((len+1)*sizeof(WCHAR));
371 memcpy(prop,ptr,len*sizeof(WCHAR));
372 prop[len]=0;
373 ptr2++;
375 len = 0;
376 ptr = ptr2;
377 while (*ptr && (quote || (!quote && *ptr!=' ')))
379 if (*ptr == '"')
380 quote = !quote;
381 ptr++;
382 len++;
385 if (*ptr2=='"')
387 ptr2++;
388 len -= 2;
390 val = msi_alloc((len+1)*sizeof(WCHAR));
391 memcpy(val,ptr2,len*sizeof(WCHAR));
392 val[len] = 0;
394 if (lstrlenW(prop) > 0)
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop), debugstr_w(val));
398 MSI_SetPropertyW(package,prop,val);
400 msi_free(val);
401 msi_free(prop);
404 return ERROR_SUCCESS;
408 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
410 LPWSTR p, *ret = NULL;
411 UINT count = 0;
413 if (!str)
414 return ret;
416 /* count the number of substrings */
417 for ( p = (LPWSTR)str, count = 0; p; count++ )
419 p = strchrW( p, sep );
420 if (p)
421 p++;
424 /* allocate space for an array of substring pointers and the substrings */
425 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
426 (lstrlenW(str)+1) * sizeof(WCHAR) );
427 if (!ret)
428 return ret;
430 /* copy the string and set the pointers */
431 p = (LPWSTR) &ret[count+1];
432 lstrcpyW( p, str );
433 for( count = 0; (ret[count] = p); count++ )
435 p = strchrW( p, sep );
436 if (p)
437 *p++ = 0;
440 return ret;
443 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
444 MSIDATABASE *patch_db, LPCWSTR name )
446 UINT ret = ERROR_FUNCTION_FAILED;
447 IStorage *stg = NULL;
448 HRESULT r;
450 TRACE("%p %s\n", package, debugstr_w(name) );
452 if (*name++ != ':')
454 ERR("expected a colon in %s\n", debugstr_w(name));
455 return ERROR_FUNCTION_FAILED;
458 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
459 if (SUCCEEDED(r))
461 ret = msi_table_apply_transform( package->db, stg );
462 IStorage_Release( stg );
463 ret = ERROR_SUCCESS;
465 else
466 ERR("failed to open substorage %s\n", debugstr_w(name));
468 return ret;
471 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
473 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list, *guids, product_id;
475 UINT i, ret = ERROR_FUNCTION_FAILED;
477 product_id = msi_dup_property( package, szProdID );
478 if (!product_id)
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS;
485 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
486 guids = msi_split_string( guid_list, ';' );
487 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
489 if (!lstrcmpW( guids[i], product_id ))
490 ret = ERROR_SUCCESS;
492 msi_free( guids );
493 msi_free( guid_list );
494 msi_free( product_id );
496 return ret;
499 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
501 MSISUMMARYINFO *si;
502 LPWSTR str, *substorage;
503 UINT i, r = ERROR_SUCCESS;
505 si = MSI_GetSummaryInformationW( patch_db, 0 );
506 if (!si)
507 return ERROR_FUNCTION_FAILED;
509 msi_check_patch_applicable( package, si );
511 /* enumerate the substorage */
512 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
513 substorage = msi_split_string( str, ';' );
514 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
515 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
516 msi_free( substorage );
517 msi_free( str );
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
521 msiobj_release( &si->hdr );
523 return r;
526 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
528 MSIDATABASE *patch_db = NULL;
529 UINT r;
531 TRACE("%p %s\n", package, debugstr_w( file ) );
533 /* FIXME:
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
538 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
539 if ( r != ERROR_SUCCESS )
541 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
542 return r;
545 msi_parse_patch_summary( package, patch_db );
546 msiobj_release( &patch_db->hdr );
548 return ERROR_SUCCESS;
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT msi_apply_patches( MSIPACKAGE *package )
554 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list, *patches;
556 UINT i, r = ERROR_SUCCESS;
558 patch_list = msi_dup_property( package, szPatch );
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
562 patches = msi_split_string( patch_list, ';' );
563 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
564 r = msi_apply_patch_package( package, patches[i] );
566 msi_free( patches );
567 msi_free( patch_list );
569 return r;
572 /****************************************************
573 * TOP level entry points
574 *****************************************************/
576 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
577 LPCWSTR szCommandLine )
579 UINT rc;
580 BOOL ui = FALSE;
581 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
582 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
583 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
585 MSI_SetPropertyW(package, szAction, szInstall);
587 package->script = msi_alloc(sizeof(MSISCRIPT));
588 memset(package->script,0,sizeof(MSISCRIPT));
590 package->script->InWhatSequence = SEQUENCE_INSTALL;
592 if (szPackagePath)
594 LPWSTR p, check, path;
596 package->PackagePath = strdupW(szPackagePath);
597 path = strdupW(szPackagePath);
598 p = strrchrW(path,'\\');
599 if (p)
601 p++;
602 *p=0;
604 else
606 msi_free(path);
607 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
608 GetCurrentDirectoryW(MAX_PATH,path);
609 strcatW(path,cszbs);
612 check = msi_dup_property( package, cszSourceDir );
613 if (!check)
614 MSI_SetPropertyW(package, cszSourceDir, path);
615 msi_free(check);
616 msi_free(path);
619 msi_parse_command_line( package, szCommandLine );
621 msi_apply_patches( package );
623 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
625 package->script->InWhatSequence |= SEQUENCE_UI;
626 rc = ACTION_ProcessUISequence(package);
627 ui = TRUE;
628 if (rc == ERROR_SUCCESS)
630 package->script->InWhatSequence |= SEQUENCE_EXEC;
631 rc = ACTION_ProcessExecSequence(package,TRUE);
634 else
635 rc = ACTION_ProcessExecSequence(package,FALSE);
637 if (rc == -1)
639 /* install was halted but should be considered a success */
640 rc = ERROR_SUCCESS;
643 package->script->CurrentlyScripting= FALSE;
645 /* process the ending type action */
646 if (rc == ERROR_SUCCESS)
647 ACTION_PerformActionSequence(package,-1,ui);
648 else if (rc == ERROR_INSTALL_USEREXIT)
649 ACTION_PerformActionSequence(package,-2,ui);
650 else if (rc == ERROR_INSTALL_SUSPEND)
651 ACTION_PerformActionSequence(package,-4,ui);
652 else /* failed */
653 ACTION_PerformActionSequence(package,-3,ui);
655 /* finish up running custom actions */
656 ACTION_FinishCustomActions(package);
658 return rc;
661 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
663 UINT rc = ERROR_SUCCESS;
664 MSIRECORD * row = 0;
665 static const WCHAR ExecSeqQuery[] =
666 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
667 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
668 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
669 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
671 static const WCHAR UISeqQuery[] =
672 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
673 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
674 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
675 ' ', '=',' ','%','i',0};
677 if (UI)
678 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
679 else
680 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
682 if (row)
684 LPCWSTR action, cond;
686 TRACE("Running the actions\n");
688 /* check conditions */
689 cond = MSI_RecordGetString(row,2);
690 if (cond)
692 /* this is a hack to skip errors in the condition code */
693 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
694 goto end;
697 action = MSI_RecordGetString(row,1);
698 if (!action)
700 ERR("failed to fetch action\n");
701 rc = ERROR_FUNCTION_FAILED;
702 goto end;
705 if (UI)
706 rc = ACTION_PerformUIAction(package,action);
707 else
708 rc = ACTION_PerformAction(package,action,FALSE);
709 end:
710 msiobj_release(&row->hdr);
712 else
713 rc = ERROR_SUCCESS;
715 return rc;
718 typedef struct {
719 MSIPACKAGE* package;
720 BOOL UI;
721 } iterate_action_param;
723 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
725 iterate_action_param *iap= (iterate_action_param*)param;
726 UINT rc;
727 LPCWSTR cond, action;
729 action = MSI_RecordGetString(row,1);
730 if (!action)
732 ERR("Error is retrieving action name\n");
733 return ERROR_FUNCTION_FAILED;
736 /* check conditions */
737 cond = MSI_RecordGetString(row,2);
738 if (cond)
740 /* this is a hack to skip errors in the condition code */
741 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
743 TRACE("Skipping action: %s (condition is false)\n",
744 debugstr_w(action));
745 return ERROR_SUCCESS;
749 if (iap->UI)
750 rc = ACTION_PerformUIAction(iap->package,action);
751 else
752 rc = ACTION_PerformAction(iap->package,action,FALSE);
754 msi_dialog_check_messages( NULL );
756 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
757 rc = iap->package->CurrentInstallState;
759 if (rc == ERROR_FUNCTION_NOT_CALLED)
760 rc = ERROR_SUCCESS;
762 if (rc != ERROR_SUCCESS)
763 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
765 return rc;
768 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
770 MSIQUERY * view;
771 UINT r;
772 static const WCHAR query[] =
773 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
774 '`','%','s','`',
775 ' ','W','H','E','R','E',' ',
776 '`','S','e','q','u','e','n','c','e','`',' ',
777 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
778 '`','S','e','q','u','e','n','c','e','`',0};
779 iterate_action_param iap;
782 * FIXME: probably should be checking UILevel in the
783 * ACTION_PerformUIAction/ACTION_PerformAction
784 * rather than saving the UI level here. Those
785 * two functions can be merged too.
787 iap.package = package;
788 iap.UI = TRUE;
790 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
792 r = MSI_OpenQuery( package->db, &view, query, szTable );
793 if (r == ERROR_SUCCESS)
795 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
796 msiobj_release(&view->hdr);
799 return r;
802 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
804 MSIQUERY * view;
805 UINT rc;
806 static const WCHAR ExecSeqQuery[] =
807 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
808 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
809 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
810 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
811 'O','R','D','E','R',' ', 'B','Y',' ',
812 '`','S','e','q','u','e','n','c','e','`',0 };
813 MSIRECORD * row = 0;
814 static const WCHAR IVQuery[] =
815 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
816 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
817 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
818 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
819 ' ','\'', 'I','n','s','t','a','l','l',
820 'V','a','l','i','d','a','t','e','\'', 0};
821 INT seq = 0;
822 iterate_action_param iap;
824 iap.package = package;
825 iap.UI = FALSE;
827 if (package->script->ExecuteSequenceRun)
829 TRACE("Execute Sequence already Run\n");
830 return ERROR_SUCCESS;
833 package->script->ExecuteSequenceRun = TRUE;
835 /* get the sequence number */
836 if (UIran)
838 row = MSI_QueryGetRecord(package->db, IVQuery);
839 if( !row )
840 return ERROR_FUNCTION_FAILED;
841 seq = MSI_RecordGetInteger(row,1);
842 msiobj_release(&row->hdr);
845 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
846 if (rc == ERROR_SUCCESS)
848 TRACE("Running the actions\n");
850 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
851 msiobj_release(&view->hdr);
854 return rc;
857 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
859 MSIQUERY * view;
860 UINT rc;
861 static const WCHAR ExecSeqQuery [] =
862 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
863 '`','I','n','s','t','a','l','l',
864 'U','I','S','e','q','u','e','n','c','e','`',
865 ' ','W','H','E','R','E',' ',
866 '`','S','e','q','u','e','n','c','e','`',' ',
867 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
868 '`','S','e','q','u','e','n','c','e','`',0};
869 iterate_action_param iap;
871 iap.package = package;
872 iap.UI = TRUE;
874 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
876 if (rc == ERROR_SUCCESS)
878 TRACE("Running the actions \n");
880 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
881 msiobj_release(&view->hdr);
884 return rc;
887 /********************************************************
888 * ACTION helper functions and functions that perform the actions
889 *******************************************************/
890 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
891 UINT* rc, BOOL force )
893 BOOL ret = FALSE;
894 BOOL run = force;
895 int i;
897 if (!run && !package->script->CurrentlyScripting)
898 run = TRUE;
900 if (!run)
902 if (strcmpW(action,szInstallFinalize) == 0 ||
903 strcmpW(action,szInstallExecute) == 0 ||
904 strcmpW(action,szInstallExecuteAgain) == 0)
905 run = TRUE;
908 i = 0;
909 while (StandardActions[i].action != NULL)
911 if (strcmpW(StandardActions[i].action, action)==0)
913 if (!run)
915 ui_actioninfo(package, action, TRUE, 0);
916 *rc = schedule_action(package,INSTALL_SCRIPT,action);
917 ui_actioninfo(package, action, FALSE, *rc);
919 else
921 ui_actionstart(package, action);
922 if (StandardActions[i].handler)
924 *rc = StandardActions[i].handler(package);
926 else
928 FIXME("unhandled standard action %s\n",debugstr_w(action));
929 *rc = ERROR_SUCCESS;
932 ret = TRUE;
933 break;
935 i++;
937 return ret;
940 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
941 UINT* rc, BOOL force )
943 BOOL ret=FALSE;
944 UINT arc;
946 arc = ACTION_CustomAction(package,action, force);
948 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
950 *rc = arc;
951 ret = TRUE;
953 return ret;
957 * A lot of actions are really important even if they don't do anything
958 * explicit... Lots of properties are set at the beginning of the installation
959 * CostFinalize does a bunch of work to translate the directories and such
961 * But until I get write access to the database that is hard, so I am going to
962 * hack it to see if I can get something to run.
964 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
966 UINT rc = ERROR_SUCCESS;
967 BOOL handled;
969 TRACE("Performing action (%s)\n",debugstr_w(action));
971 handled = ACTION_HandleStandardAction(package, action, &rc, force);
973 if (!handled)
974 handled = ACTION_HandleCustomAction(package, action, &rc, force);
976 if (!handled)
978 FIXME("unhandled msi action %s\n",debugstr_w(action));
979 rc = ERROR_FUNCTION_NOT_CALLED;
982 return rc;
985 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
987 UINT rc = ERROR_SUCCESS;
988 BOOL handled = FALSE;
990 TRACE("Performing action (%s)\n",debugstr_w(action));
992 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
994 if (!handled)
995 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
997 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
998 handled = TRUE;
1000 if (!handled)
1002 FIXME("unhandled msi action %s\n",debugstr_w(action));
1003 rc = ERROR_FUNCTION_NOT_CALLED;
1006 return rc;
1011 * Actual Action Handlers
1014 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1016 MSIPACKAGE *package = (MSIPACKAGE*)param;
1017 LPCWSTR dir;
1018 LPWSTR full_path;
1019 MSIRECORD *uirow;
1020 MSIFOLDER *folder;
1022 dir = MSI_RecordGetString(row,1);
1023 if (!dir)
1025 ERR("Unable to get folder id \n");
1026 return ERROR_SUCCESS;
1029 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1030 if (!full_path)
1032 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1033 return ERROR_SUCCESS;
1036 TRACE("Folder is %s\n",debugstr_w(full_path));
1038 /* UI stuff */
1039 uirow = MSI_CreateRecord(1);
1040 MSI_RecordSetStringW(uirow,1,full_path);
1041 ui_actiondata(package,szCreateFolders,uirow);
1042 msiobj_release( &uirow->hdr );
1044 if (folder->State == 0)
1045 create_full_pathW(full_path);
1047 folder->State = 3;
1049 msi_free(full_path);
1050 return ERROR_SUCCESS;
1053 /* FIXME: probably should merge this with the above function */
1054 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1056 UINT rc = ERROR_SUCCESS;
1057 MSIFOLDER *folder;
1058 LPWSTR install_path;
1060 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1061 if (!install_path)
1062 return ERROR_FUNCTION_FAILED;
1064 /* create the path */
1065 if (folder->State == 0)
1067 create_full_pathW(install_path);
1068 folder->State = 2;
1070 msi_free(install_path);
1072 return rc;
1075 UINT msi_create_component_directories( MSIPACKAGE *package )
1077 MSICOMPONENT *comp;
1079 /* create all the folders required by the components are going to install */
1080 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1082 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1083 continue;
1084 msi_create_directory( package, comp->Directory );
1087 return ERROR_SUCCESS;
1091 * Also we cannot enable/disable components either, so for now I am just going
1092 * to do all the directories for all the components.
1094 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1096 static const WCHAR ExecSeqQuery[] =
1097 {'S','E','L','E','C','T',' ',
1098 '`','D','i','r','e','c','t','o','r','y','_','`',
1099 ' ','F','R','O','M',' ',
1100 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1101 UINT rc;
1102 MSIQUERY *view;
1104 /* create all the empty folders specified in the CreateFolder table */
1105 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1106 if (rc != ERROR_SUCCESS)
1107 return ERROR_SUCCESS;
1109 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1110 msiobj_release(&view->hdr);
1112 msi_create_component_directories( package );
1114 return rc;
1117 static MSICOMPONENT* load_component( MSIRECORD * row )
1119 MSICOMPONENT *comp;
1121 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1122 if (!comp)
1123 return comp;
1125 /* fill in the data */
1126 comp->Component = msi_dup_record_field( row, 1 );
1128 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1130 comp->ComponentId = msi_dup_record_field( row, 2 );
1131 comp->Directory = msi_dup_record_field( row, 3 );
1132 comp->Attributes = MSI_RecordGetInteger(row,4);
1133 comp->Condition = msi_dup_record_field( row, 5 );
1134 comp->KeyPath = msi_dup_record_field( row, 6 );
1136 comp->Installed = INSTALLSTATE_ABSENT;
1137 comp->Action = INSTALLSTATE_UNKNOWN;
1138 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1140 comp->Enabled = TRUE;
1142 return comp;
1145 typedef struct {
1146 MSIPACKAGE *package;
1147 MSIFEATURE *feature;
1148 } _ilfs;
1150 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1152 ComponentList *cl;
1154 cl = msi_alloc( sizeof (*cl) );
1155 if ( !cl )
1156 return ERROR_NOT_ENOUGH_MEMORY;
1157 cl->component = comp;
1158 list_add_tail( &feature->Components, &cl->entry );
1160 return ERROR_SUCCESS;
1163 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1165 _ilfs* ilfs= (_ilfs*)param;
1166 MSIPACKAGE *package = ilfs->package;
1167 MSIFEATURE *feature = ilfs->feature;
1168 MSICOMPONENT *comp;
1170 comp = load_component( row );
1171 if (!comp)
1172 return ERROR_FUNCTION_FAILED;
1174 list_add_tail( &package->components, &comp->entry );
1175 add_feature_component( feature, comp );
1177 TRACE("Loaded new component %p\n", comp);
1179 return ERROR_SUCCESS;
1182 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1184 _ilfs* ilfs= (_ilfs*)param;
1185 LPCWSTR component;
1186 DWORD rc;
1187 MSICOMPONENT *comp;
1188 MSIQUERY * view;
1189 static const WCHAR Query[] =
1190 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1191 '`','C','o','m','p','o','n','e','n','t','`',' ',
1192 'W','H','E','R','E',' ',
1193 '`','C','o','m','p','o','n','e','n','t','`',' ',
1194 '=','\'','%','s','\'',0};
1196 component = MSI_RecordGetString(row,1);
1198 /* check to see if the component is already loaded */
1199 comp = get_loaded_component( ilfs->package, component );
1200 if (comp)
1202 TRACE("Component %s already loaded\n", debugstr_w(component) );
1203 add_feature_component( ilfs->feature, comp );
1204 return ERROR_SUCCESS;
1207 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1208 if (rc != ERROR_SUCCESS)
1209 return ERROR_SUCCESS;
1211 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1212 msiobj_release( &view->hdr );
1214 return ERROR_SUCCESS;
1217 static UINT load_feature(MSIRECORD * row, LPVOID param)
1219 MSIPACKAGE* package = (MSIPACKAGE*)param;
1220 MSIFEATURE* feature;
1221 static const WCHAR Query1[] =
1222 {'S','E','L','E','C','T',' ',
1223 '`','C','o','m','p','o','n','e','n','t','_','`',
1224 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1225 'C','o','m','p','o','n','e','n','t','s','`',' ',
1226 'W','H','E','R','E',' ',
1227 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1228 MSIQUERY * view;
1229 UINT rc;
1230 _ilfs ilfs;
1232 /* fill in the data */
1234 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1235 if (!feature)
1236 return ERROR_NOT_ENOUGH_MEMORY;
1238 list_init( &feature->Components );
1240 feature->Feature = msi_dup_record_field( row, 1 );
1242 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1244 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1245 feature->Title = msi_dup_record_field( row, 3 );
1246 feature->Description = msi_dup_record_field( row, 4 );
1248 if (!MSI_RecordIsNull(row,5))
1249 feature->Display = MSI_RecordGetInteger(row,5);
1251 feature->Level= MSI_RecordGetInteger(row,6);
1252 feature->Directory = msi_dup_record_field( row, 7 );
1253 feature->Attributes = MSI_RecordGetInteger(row,8);
1255 feature->Installed = INSTALLSTATE_ABSENT;
1256 feature->Action = INSTALLSTATE_UNKNOWN;
1257 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1259 list_add_tail( &package->features, &feature->entry );
1261 /* load feature components */
1263 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1264 if (rc != ERROR_SUCCESS)
1265 return ERROR_SUCCESS;
1267 ilfs.package = package;
1268 ilfs.feature = feature;
1270 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1271 msiobj_release(&view->hdr);
1273 return ERROR_SUCCESS;
1276 static UINT load_file(MSIRECORD *row, LPVOID param)
1278 MSIPACKAGE* package = (MSIPACKAGE*)param;
1279 LPCWSTR component;
1280 MSIFILE *file;
1282 /* fill in the data */
1284 file = msi_alloc_zero( sizeof (MSIFILE) );
1285 if (!file)
1286 return ERROR_NOT_ENOUGH_MEMORY;
1288 file->File = msi_dup_record_field( row, 1 );
1290 component = MSI_RecordGetString( row, 2 );
1291 file->Component = get_loaded_component( package, component );
1293 if (!file->Component)
1294 ERR("Unfound Component %s\n",debugstr_w(component));
1296 file->FileName = msi_dup_record_field( row, 3 );
1297 reduce_to_longfilename( file->FileName );
1299 file->ShortName = msi_dup_record_field( row, 3 );
1300 reduce_to_shortfilename( file->ShortName );
1302 file->FileSize = MSI_RecordGetInteger( row, 4 );
1303 file->Version = msi_dup_record_field( row, 5 );
1304 file->Language = msi_dup_record_field( row, 6 );
1305 file->Attributes = MSI_RecordGetInteger( row, 7 );
1306 file->Sequence = MSI_RecordGetInteger( row, 8 );
1308 file->State = 0;
1310 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1312 list_add_tail( &package->files, &file->entry );
1314 return ERROR_SUCCESS;
1317 static UINT load_all_files(MSIPACKAGE *package)
1319 MSIQUERY * view;
1320 UINT rc;
1321 static const WCHAR Query[] =
1322 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1323 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1324 '`','S','e','q','u','e','n','c','e','`', 0};
1326 if (!package)
1327 return ERROR_INVALID_HANDLE;
1329 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1330 if (rc != ERROR_SUCCESS)
1331 return ERROR_SUCCESS;
1333 rc = MSI_IterateRecords(view, NULL, load_file, package);
1334 msiobj_release(&view->hdr);
1336 return ERROR_SUCCESS;
1341 * I am not doing any of the costing functionality yet.
1342 * Mostly looking at doing the Component and Feature loading
1344 * The native MSI does A LOT of modification to tables here. Mostly adding
1345 * a lot of temporary columns to the Feature and Component tables.
1347 * note: Native msi also tracks the short filename. But I am only going to
1348 * track the long ones. Also looking at this directory table
1349 * it appears that the directory table does not get the parents
1350 * resolved base on property only based on their entries in the
1351 * directory table.
1353 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1355 MSIQUERY * view;
1356 UINT rc;
1357 static const WCHAR Query_all[] =
1358 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1359 '`','F','e','a','t','u','r','e','`',0};
1360 static const WCHAR szCosting[] =
1361 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1362 static const WCHAR szZero[] = { '0', 0 };
1364 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1365 return ERROR_SUCCESS;
1367 MSI_SetPropertyW(package, szCosting, szZero);
1368 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1370 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1371 if (rc != ERROR_SUCCESS)
1372 return rc;
1374 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1375 msiobj_release(&view->hdr);
1377 load_all_files(package);
1379 return ERROR_SUCCESS;
1382 static UINT execute_script(MSIPACKAGE *package, UINT script )
1384 int i;
1385 UINT rc = ERROR_SUCCESS;
1387 TRACE("Executing Script %i\n",script);
1389 for (i = 0; i < package->script->ActionCount[script]; i++)
1391 LPWSTR action;
1392 action = package->script->Actions[script][i];
1393 ui_actionstart(package, action);
1394 TRACE("Executing Action (%s)\n",debugstr_w(action));
1395 rc = ACTION_PerformAction(package, action, TRUE);
1396 msi_free(package->script->Actions[script][i]);
1397 if (rc != ERROR_SUCCESS)
1398 break;
1400 msi_free(package->script->Actions[script]);
1402 package->script->ActionCount[script] = 0;
1403 package->script->Actions[script] = NULL;
1404 return rc;
1407 static UINT ACTION_FileCost(MSIPACKAGE *package)
1409 return ERROR_SUCCESS;
1413 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1415 static const WCHAR Query[] =
1416 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1417 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1418 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1419 ' ','=',' ','\'','%','s','\'',
1421 LPWSTR ptargetdir, targetdir, srcdir;
1422 LPCWSTR parent;
1423 LPWSTR shortname = NULL;
1424 MSIRECORD * row = 0;
1425 MSIFOLDER *folder;
1427 TRACE("Looking for dir %s\n",debugstr_w(dir));
1429 folder = get_loaded_folder( package, dir );
1430 if (folder)
1431 return folder;
1433 TRACE("Working to load %s\n",debugstr_w(dir));
1435 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1436 if (!folder)
1437 return NULL;
1439 folder->Directory = strdupW(dir);
1441 row = MSI_QueryGetRecord(package->db, Query, dir);
1442 if (!row)
1443 return NULL;
1445 ptargetdir = targetdir = msi_dup_record_field(row,3);
1447 /* split src and target dir */
1448 if (strchrW(targetdir,':'))
1450 srcdir=strchrW(targetdir,':');
1451 *srcdir=0;
1452 srcdir ++;
1454 else
1455 srcdir=NULL;
1457 /* for now only pick long filename versions */
1458 if (strchrW(targetdir,'|'))
1460 shortname = targetdir;
1461 targetdir = strchrW(targetdir,'|');
1462 *targetdir = 0;
1463 targetdir ++;
1465 /* for the sourcedir pick the short filename */
1466 if (srcdir && strchrW(srcdir,'|'))
1468 LPWSTR p = strchrW(srcdir,'|');
1469 *p = 0;
1472 /* now check for root dirs */
1473 if (targetdir[0] == '.' && targetdir[1] == 0)
1474 targetdir = NULL;
1476 if (targetdir)
1478 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1479 msi_free( folder->TargetDefault);
1480 folder->TargetDefault = strdupW(targetdir);
1483 if (srcdir)
1484 folder->SourceDefault = strdupW(srcdir);
1485 else if (shortname)
1486 folder->SourceDefault = strdupW(shortname);
1487 else if (targetdir)
1488 folder->SourceDefault = strdupW(targetdir);
1489 msi_free(ptargetdir);
1490 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1492 parent = MSI_RecordGetString(row,2);
1493 if (parent)
1495 folder->Parent = load_folder( package, parent );
1496 if ( folder->Parent )
1497 TRACE("loaded parent %p %s\n", folder->Parent,
1498 debugstr_w(folder->Parent->Directory));
1499 else
1500 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1503 folder->Property = msi_dup_property( package, dir );
1505 msiobj_release(&row->hdr);
1507 list_add_tail( &package->folders, &folder->entry );
1509 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1511 return folder;
1514 /* scan for and update current install states */
1515 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1517 MSICOMPONENT *comp;
1518 MSIFEATURE *feature;
1520 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1522 INSTALLSTATE res;
1523 res = MsiGetComponentPathW( package->ProductCode,
1524 comp->ComponentId, NULL, NULL);
1525 if (res < 0)
1526 res = INSTALLSTATE_ABSENT;
1527 comp->Installed = res;
1530 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1532 ComponentList *cl;
1533 INSTALLSTATE res = -10;
1535 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1537 comp= cl->component;
1539 if (res == -10)
1540 res = comp->Installed;
1541 else
1543 if (res == comp->Installed)
1544 continue;
1546 if (res != comp->Installed)
1547 res = INSTALLSTATE_INCOMPLETE;
1550 feature->Installed = res;
1554 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1555 INSTALLSTATE state)
1557 static const WCHAR all[]={'A','L','L',0};
1558 LPWSTR override;
1559 MSIFEATURE *feature;
1561 override = msi_dup_property( package, property );
1562 if (!override)
1563 return FALSE;
1565 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1567 if (strcmpiW(override,all)==0)
1569 feature->ActionRequest= state;
1570 feature->Action = state;
1572 else
1574 LPWSTR ptr = override;
1575 LPWSTR ptr2 = strchrW(override,',');
1577 while (ptr)
1579 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1580 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1582 feature->ActionRequest= state;
1583 feature->Action = state;
1584 break;
1586 if (ptr2)
1588 ptr=ptr2+1;
1589 ptr2 = strchrW(ptr,',');
1591 else
1592 break;
1596 msi_free(override);
1598 return TRUE;
1601 static UINT SetFeatureStates(MSIPACKAGE *package)
1603 int install_level;
1604 static const WCHAR szlevel[] =
1605 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1606 static const WCHAR szAddLocal[] =
1607 {'A','D','D','L','O','C','A','L',0};
1608 static const WCHAR szRemove[] =
1609 {'R','E','M','O','V','E',0};
1610 BOOL override = FALSE;
1611 MSICOMPONENT* component;
1612 MSIFEATURE *feature;
1615 /* I do not know if this is where it should happen.. but */
1617 TRACE("Checking Install Level\n");
1619 install_level = msi_get_property_int( package, szlevel, 1 );
1621 /* ok hereis the _real_ rub
1622 * all these activation/deactivation things happen in order and things
1623 * later on the list override things earlier on the list.
1624 * 1) INSTALLLEVEL processing
1625 * 2) ADDLOCAL
1626 * 3) REMOVE
1627 * 4) ADDSOURCE
1628 * 5) ADDDEFAULT
1629 * 6) REINSTALL
1630 * 7) COMPADDLOCAL
1631 * 8) COMPADDSOURCE
1632 * 9) FILEADDLOCAL
1633 * 10) FILEADDSOURCE
1634 * 11) FILEADDDEFAULT
1635 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1636 * ignored for all the features. seems strange, especially since it is not
1637 * documented anywhere, but it is how it works.
1639 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1640 * REMOVE are the big ones, since we don't handle administrative installs
1641 * yet anyway.
1643 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1644 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1646 if (!override)
1648 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1650 BOOL feature_state = ((feature->Level > 0) &&
1651 (feature->Level <= install_level));
1653 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1655 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1657 feature->ActionRequest = INSTALLSTATE_SOURCE;
1658 feature->Action = INSTALLSTATE_SOURCE;
1660 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1662 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1663 feature->Action = INSTALLSTATE_ADVERTISED;
1665 else
1667 feature->ActionRequest = INSTALLSTATE_LOCAL;
1668 feature->Action = INSTALLSTATE_LOCAL;
1673 else
1675 /* set the Preselected Property */
1676 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1677 static const WCHAR szOne[] = { '1', 0 };
1679 MSI_SetPropertyW(package,szPreselected,szOne);
1683 * now we want to enable or disable components base on feature
1686 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1688 ComponentList *cl;
1690 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1691 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1692 feature->ActionRequest);
1694 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1696 component = cl->component;
1698 if (!component->Enabled)
1700 component->Action = INSTALLSTATE_UNKNOWN;
1701 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1703 else
1705 if (feature->Action == INSTALLSTATE_LOCAL)
1707 component->Action = INSTALLSTATE_LOCAL;
1708 component->ActionRequest = INSTALLSTATE_LOCAL;
1710 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1712 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1713 (component->Action == INSTALLSTATE_ABSENT) ||
1714 (component->Action == INSTALLSTATE_ADVERTISED))
1717 component->Action = INSTALLSTATE_SOURCE;
1718 component->ActionRequest = INSTALLSTATE_SOURCE;
1721 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1723 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1724 (component->Action == INSTALLSTATE_ABSENT))
1727 component->Action = INSTALLSTATE_ADVERTISED;
1728 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1731 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1733 if (component->Action == INSTALLSTATE_UNKNOWN)
1735 component->Action = INSTALLSTATE_ABSENT;
1736 component->ActionRequest = INSTALLSTATE_ABSENT;
1743 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1745 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1746 debugstr_w(component->Component), component->Installed,
1747 component->Action, component->ActionRequest);
1751 return ERROR_SUCCESS;
1754 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1756 MSIPACKAGE *package = (MSIPACKAGE*)param;
1757 LPCWSTR name;
1758 LPWSTR path;
1760 name = MSI_RecordGetString(row,1);
1762 /* This helper function now does ALL the work */
1763 TRACE("Dir %s ...\n",debugstr_w(name));
1764 load_folder(package,name);
1765 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1766 TRACE("resolves to %s\n",debugstr_w(path));
1767 msi_free(path);
1769 return ERROR_SUCCESS;
1772 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1774 MSIPACKAGE *package = (MSIPACKAGE*)param;
1775 LPCWSTR name;
1776 MSIFEATURE *feature;
1778 name = MSI_RecordGetString( row, 1 );
1780 feature = get_loaded_feature( package, name );
1781 if (!feature)
1782 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1783 else
1785 LPCWSTR Condition;
1786 Condition = MSI_RecordGetString(row,3);
1788 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1790 int level = MSI_RecordGetInteger(row,2);
1791 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1792 feature->Level = level;
1795 return ERROR_SUCCESS;
1800 * A lot is done in this function aside from just the costing.
1801 * The costing needs to be implemented at some point but for now I am going
1802 * to focus on the directory building
1805 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1807 static const WCHAR ExecSeqQuery[] =
1808 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1809 '`','D','i','r','e','c','t','o','r','y','`',0};
1810 static const WCHAR ConditionQuery[] =
1811 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1812 '`','C','o','n','d','i','t','i','o','n','`',0};
1813 static const WCHAR szCosting[] =
1814 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1815 static const WCHAR szlevel[] =
1816 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1817 static const WCHAR szOne[] = { '1', 0 };
1818 MSICOMPONENT *comp;
1819 MSIFILE *file;
1820 UINT rc;
1821 MSIQUERY * view;
1822 LPWSTR level;
1824 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1825 return ERROR_SUCCESS;
1827 TRACE("Building Directory properties\n");
1829 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1830 if (rc == ERROR_SUCCESS)
1832 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1833 package);
1834 msiobj_release(&view->hdr);
1837 TRACE("File calculations\n");
1839 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1841 MSICOMPONENT* comp = file->Component;
1842 LPWSTR p;
1844 if (!comp)
1845 continue;
1847 /* calculate target */
1848 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1850 msi_free(file->TargetPath);
1852 TRACE("file %s is named %s\n",
1853 debugstr_w(file->File),debugstr_w(file->FileName));
1855 file->TargetPath = build_directory_name(2, p, file->FileName);
1857 msi_free(p);
1859 TRACE("file %s resolves to %s\n",
1860 debugstr_w(file->File),debugstr_w(file->TargetPath));
1862 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1864 file->State = 1;
1865 comp->Cost += file->FileSize;
1866 continue;
1869 if (file->Version)
1871 DWORD handle;
1872 DWORD versize;
1873 UINT sz;
1874 LPVOID version;
1875 static const WCHAR name[] =
1876 {'\\',0};
1877 static const WCHAR name_fmt[] =
1878 {'%','u','.','%','u','.','%','u','.','%','u',0};
1879 WCHAR filever[0x100];
1880 VS_FIXEDFILEINFO *lpVer;
1882 TRACE("Version comparison.. \n");
1883 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1884 version = msi_alloc(versize);
1885 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1887 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1889 sprintfW(filever,name_fmt,
1890 HIWORD(lpVer->dwFileVersionMS),
1891 LOWORD(lpVer->dwFileVersionMS),
1892 HIWORD(lpVer->dwFileVersionLS),
1893 LOWORD(lpVer->dwFileVersionLS));
1895 TRACE("new %s old %s\n", debugstr_w(file->Version),
1896 debugstr_w(filever));
1897 if (strcmpiW(filever,file->Version)<0)
1899 file->State = 2;
1900 FIXME("cost should be diff in size\n");
1901 comp->Cost += file->FileSize;
1903 else
1904 file->State = 3;
1905 msi_free(version);
1907 else
1908 file->State = 3;
1911 TRACE("Evaluating Condition Table\n");
1913 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1914 if (rc == ERROR_SUCCESS)
1916 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1917 package);
1918 msiobj_release(&view->hdr);
1921 TRACE("Enabling or Disabling Components\n");
1922 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1924 if (comp->Condition)
1926 if (MSI_EvaluateConditionW(package,
1927 comp->Condition) == MSICONDITION_FALSE)
1929 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1930 comp->Enabled = FALSE;
1935 MSI_SetPropertyW(package,szCosting,szOne);
1936 /* set default run level if not set */
1937 level = msi_dup_property( package, szlevel );
1938 if (!level)
1939 MSI_SetPropertyW(package,szlevel, szOne);
1940 msi_free(level);
1942 ACTION_UpdateInstallStates(package);
1944 return SetFeatureStates(package);
1947 /* OK this value is "interpreted" and then formatted based on the
1948 first few characters */
1949 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1950 DWORD *size)
1952 LPSTR data = NULL;
1953 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1955 if (value[1]=='x')
1957 LPWSTR ptr;
1958 CHAR byte[5];
1959 LPWSTR deformated = NULL;
1960 int count;
1962 deformat_string(package, &value[2], &deformated);
1964 /* binary value type */
1965 ptr = deformated;
1966 *type = REG_BINARY;
1967 if (strlenW(ptr)%2)
1968 *size = (strlenW(ptr)/2)+1;
1969 else
1970 *size = strlenW(ptr)/2;
1972 data = msi_alloc(*size);
1974 byte[0] = '0';
1975 byte[1] = 'x';
1976 byte[4] = 0;
1977 count = 0;
1978 /* if uneven pad with a zero in front */
1979 if (strlenW(ptr)%2)
1981 byte[2]= '0';
1982 byte[3]= *ptr;
1983 ptr++;
1984 data[count] = (BYTE)strtol(byte,NULL,0);
1985 count ++;
1986 TRACE("Uneven byte count\n");
1988 while (*ptr)
1990 byte[2]= *ptr;
1991 ptr++;
1992 byte[3]= *ptr;
1993 ptr++;
1994 data[count] = (BYTE)strtol(byte,NULL,0);
1995 count ++;
1997 msi_free(deformated);
1999 TRACE("Data %li bytes(%i)\n",*size,count);
2001 else
2003 LPWSTR deformated;
2004 LPWSTR p;
2005 DWORD d = 0;
2006 deformat_string(package, &value[1], &deformated);
2008 *type=REG_DWORD;
2009 *size = sizeof(DWORD);
2010 data = msi_alloc(*size);
2011 p = deformated;
2012 if (*p == '-')
2013 p++;
2014 while (*p)
2016 if ( (*p < '0') || (*p > '9') )
2017 break;
2018 d *= 10;
2019 d += (*p - '0');
2020 p++;
2022 if (deformated[0] == '-')
2023 d = -d;
2024 *(LPDWORD)data = d;
2025 TRACE("DWORD %li\n",*(LPDWORD)data);
2027 msi_free(deformated);
2030 else
2032 static const WCHAR szMulti[] = {'[','~',']',0};
2033 LPCWSTR ptr;
2034 *type=REG_SZ;
2036 if (value[0]=='#')
2038 if (value[1]=='%')
2040 ptr = &value[2];
2041 *type=REG_EXPAND_SZ;
2043 else
2044 ptr = &value[1];
2046 else
2047 ptr=value;
2049 if (strstrW(value,szMulti))
2050 *type = REG_MULTI_SZ;
2052 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2054 return data;
2057 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2059 MSIPACKAGE *package = (MSIPACKAGE*)param;
2060 static const WCHAR szHCR[] =
2061 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2062 'R','O','O','T','\\',0};
2063 static const WCHAR szHCU[] =
2064 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2065 'U','S','E','R','\\',0};
2066 static const WCHAR szHLM[] =
2067 {'H','K','E','Y','_','L','O','C','A','L','_',
2068 'M','A','C','H','I','N','E','\\',0};
2069 static const WCHAR szHU[] =
2070 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2072 LPSTR value_data = NULL;
2073 HKEY root_key, hkey;
2074 DWORD type,size;
2075 LPWSTR deformated;
2076 LPCWSTR szRoot, component, name, key, value;
2077 MSICOMPONENT *comp;
2078 MSIRECORD * uirow;
2079 LPWSTR uikey;
2080 INT root;
2081 BOOL check_first = FALSE;
2082 UINT rc;
2084 ui_progress(package,2,0,0,0);
2086 value = NULL;
2087 key = NULL;
2088 uikey = NULL;
2089 name = NULL;
2091 component = MSI_RecordGetString(row, 6);
2092 comp = get_loaded_component(package,component);
2093 if (!comp)
2094 return ERROR_SUCCESS;
2096 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2098 TRACE("Skipping write due to disabled component %s\n",
2099 debugstr_w(component));
2101 comp->Action = comp->Installed;
2103 return ERROR_SUCCESS;
2106 comp->Action = INSTALLSTATE_LOCAL;
2108 name = MSI_RecordGetString(row, 4);
2109 if( MSI_RecordIsNull(row,5) && name )
2111 /* null values can have special meanings */
2112 if (name[0]=='-' && name[1] == 0)
2113 return ERROR_SUCCESS;
2114 else if ((name[0]=='+' && name[1] == 0) ||
2115 (name[0] == '*' && name[1] == 0))
2116 name = NULL;
2117 check_first = TRUE;
2120 root = MSI_RecordGetInteger(row,2);
2121 key = MSI_RecordGetString(row, 3);
2123 /* get the root key */
2124 switch (root)
2126 case -1:
2128 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2129 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2130 if (all_users && all_users[0] == '1')
2132 root_key = HKEY_LOCAL_MACHINE;
2133 szRoot = szHLM;
2135 else
2137 root_key = HKEY_CURRENT_USER;
2138 szRoot = szHCU;
2140 msi_free(all_users);
2142 break;
2143 case 0: root_key = HKEY_CLASSES_ROOT;
2144 szRoot = szHCR;
2145 break;
2146 case 1: root_key = HKEY_CURRENT_USER;
2147 szRoot = szHCU;
2148 break;
2149 case 2: root_key = HKEY_LOCAL_MACHINE;
2150 szRoot = szHLM;
2151 break;
2152 case 3: root_key = HKEY_USERS;
2153 szRoot = szHU;
2154 break;
2155 default:
2156 ERR("Unknown root %i\n",root);
2157 root_key=NULL;
2158 szRoot = NULL;
2159 break;
2161 if (!root_key)
2162 return ERROR_SUCCESS;
2164 deformat_string(package, key , &deformated);
2165 size = strlenW(deformated) + strlenW(szRoot) + 1;
2166 uikey = msi_alloc(size*sizeof(WCHAR));
2167 strcpyW(uikey,szRoot);
2168 strcatW(uikey,deformated);
2170 if (RegCreateKeyW( root_key, deformated, &hkey))
2172 ERR("Could not create key %s\n",debugstr_w(deformated));
2173 msi_free(deformated);
2174 msi_free(uikey);
2175 return ERROR_SUCCESS;
2177 msi_free(deformated);
2179 value = MSI_RecordGetString(row,5);
2180 if (value)
2181 value_data = parse_value(package, value, &type, &size);
2182 else
2184 static const WCHAR szEmpty[] = {0};
2185 value_data = (LPSTR)strdupW(szEmpty);
2186 size = 0;
2187 type = REG_SZ;
2190 deformat_string(package, name, &deformated);
2192 /* get the double nulls to terminate SZ_MULTI */
2193 if (type == REG_MULTI_SZ)
2194 size +=sizeof(WCHAR);
2196 if (!check_first)
2198 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2199 debugstr_w(uikey));
2200 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2202 else
2204 DWORD sz = 0;
2205 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2206 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2208 TRACE("value %s of %s checked already exists\n",
2209 debugstr_w(deformated), debugstr_w(uikey));
2211 else
2213 TRACE("Checked and setting value %s of %s\n",
2214 debugstr_w(deformated), debugstr_w(uikey));
2215 if (deformated || size)
2216 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2219 RegCloseKey(hkey);
2221 uirow = MSI_CreateRecord(3);
2222 MSI_RecordSetStringW(uirow,2,deformated);
2223 MSI_RecordSetStringW(uirow,1,uikey);
2225 if (type == REG_SZ)
2226 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2227 else
2228 MSI_RecordSetStringW(uirow,3,value);
2230 ui_actiondata(package,szWriteRegistryValues,uirow);
2231 msiobj_release( &uirow->hdr );
2233 msi_free(value_data);
2234 msi_free(deformated);
2235 msi_free(uikey);
2237 return ERROR_SUCCESS;
2240 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2242 UINT rc;
2243 MSIQUERY * view;
2244 static const WCHAR ExecSeqQuery[] =
2245 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2246 '`','R','e','g','i','s','t','r','y','`',0 };
2248 if (!package)
2249 return ERROR_INVALID_HANDLE;
2251 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2252 if (rc != ERROR_SUCCESS)
2253 return ERROR_SUCCESS;
2255 /* increment progress bar each time action data is sent */
2256 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2258 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2260 msiobj_release(&view->hdr);
2261 return rc;
2264 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2266 package->script->CurrentlyScripting = TRUE;
2268 return ERROR_SUCCESS;
2272 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2274 MSICOMPONENT *comp;
2275 DWORD progress = 0;
2276 DWORD total = 0;
2277 static const WCHAR q1[]=
2278 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2279 '`','R','e','g','i','s','t','r','y','`',0};
2280 UINT rc;
2281 MSIQUERY * view;
2282 MSIFEATURE *feature;
2283 MSIFILE *file;
2285 TRACE("InstallValidate\n");
2287 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2288 if (rc == ERROR_SUCCESS)
2290 MSI_IterateRecords( view, &progress, NULL, package );
2291 msiobj_release( &view->hdr );
2292 total += progress * REG_PROGRESS_VALUE;
2295 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2296 total += COMPONENT_PROGRESS_VALUE;
2298 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2299 total += file->FileSize;
2301 ui_progress(package,0,total,0,0);
2303 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2305 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2306 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2307 feature->ActionRequest);
2310 return ERROR_SUCCESS;
2313 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2315 MSIPACKAGE* package = (MSIPACKAGE*)param;
2316 LPCWSTR cond = NULL;
2317 LPCWSTR message = NULL;
2318 static const WCHAR title[]=
2319 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2321 cond = MSI_RecordGetString(row,1);
2323 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2325 LPWSTR deformated;
2326 message = MSI_RecordGetString(row,2);
2327 deformat_string(package,message,&deformated);
2328 MessageBoxW(NULL,deformated,title,MB_OK);
2329 msi_free(deformated);
2330 return ERROR_FUNCTION_FAILED;
2333 return ERROR_SUCCESS;
2336 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2338 UINT rc;
2339 MSIQUERY * view = NULL;
2340 static const WCHAR ExecSeqQuery[] =
2341 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2342 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2344 TRACE("Checking launch conditions\n");
2346 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2347 if (rc != ERROR_SUCCESS)
2348 return ERROR_SUCCESS;
2350 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2351 msiobj_release(&view->hdr);
2353 return rc;
2356 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2359 if (!cmp->KeyPath)
2360 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2362 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2364 MSIRECORD * row = 0;
2365 UINT root,len;
2366 LPWSTR deformated,buffer,deformated_name;
2367 LPCWSTR key,name;
2368 static const WCHAR ExecSeqQuery[] =
2369 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2370 '`','R','e','g','i','s','t','r','y','`',' ',
2371 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2372 ' ','=',' ' ,'\'','%','s','\'',0 };
2373 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2374 static const WCHAR fmt2[]=
2375 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2377 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2378 if (!row)
2379 return NULL;
2381 root = MSI_RecordGetInteger(row,2);
2382 key = MSI_RecordGetString(row, 3);
2383 name = MSI_RecordGetString(row, 4);
2384 deformat_string(package, key , &deformated);
2385 deformat_string(package, name, &deformated_name);
2387 len = strlenW(deformated) + 6;
2388 if (deformated_name)
2389 len+=strlenW(deformated_name);
2391 buffer = msi_alloc( len *sizeof(WCHAR));
2393 if (deformated_name)
2394 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2395 else
2396 sprintfW(buffer,fmt,root,deformated);
2398 msi_free(deformated);
2399 msi_free(deformated_name);
2400 msiobj_release(&row->hdr);
2402 return buffer;
2404 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2406 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2407 return NULL;
2409 else
2411 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2413 if (file)
2414 return strdupW( file->TargetPath );
2416 return NULL;
2419 static HKEY openSharedDLLsKey(void)
2421 HKEY hkey=0;
2422 static const WCHAR path[] =
2423 {'S','o','f','t','w','a','r','e','\\',
2424 'M','i','c','r','o','s','o','f','t','\\',
2425 'W','i','n','d','o','w','s','\\',
2426 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2427 'S','h','a','r','e','d','D','L','L','s',0};
2429 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2430 return hkey;
2433 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2435 HKEY hkey;
2436 DWORD count=0;
2437 DWORD type;
2438 DWORD sz = sizeof(count);
2439 DWORD rc;
2441 hkey = openSharedDLLsKey();
2442 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2443 if (rc != ERROR_SUCCESS)
2444 count = 0;
2445 RegCloseKey(hkey);
2446 return count;
2449 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2451 HKEY hkey;
2453 hkey = openSharedDLLsKey();
2454 if (count > 0)
2455 msi_reg_set_val_dword( hkey, path, count );
2456 else
2457 RegDeleteValueW(hkey,path);
2458 RegCloseKey(hkey);
2459 return count;
2463 * Return TRUE if the count should be written out and FALSE if not
2465 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2467 MSIFEATURE *feature;
2468 INT count = 0;
2469 BOOL write = FALSE;
2471 /* only refcount DLLs */
2472 if (comp->KeyPath == NULL ||
2473 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2474 comp->Attributes & msidbComponentAttributesODBCDataSource)
2475 write = FALSE;
2476 else
2478 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2479 write = (count > 0);
2481 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2482 write = TRUE;
2485 /* increment counts */
2486 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2488 ComponentList *cl;
2490 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2491 continue;
2493 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2495 if ( cl->component == comp )
2496 count++;
2500 /* decrement counts */
2501 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2503 ComponentList *cl;
2505 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2506 continue;
2508 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2510 if ( cl->component == comp )
2511 count--;
2515 /* ref count all the files in the component */
2516 if (write)
2518 MSIFILE *file;
2520 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2522 if (file->Component == comp)
2523 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2527 /* add a count for permenent */
2528 if (comp->Attributes & msidbComponentAttributesPermanent)
2529 count ++;
2531 comp->RefCount = count;
2533 if (write)
2534 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2538 * Ok further analysis makes me think that this work is
2539 * actually done in the PublishComponents and PublishFeatures
2540 * step, and not here. It appears like the keypath and all that is
2541 * resolved in this step, however actually written in the Publish steps.
2542 * But we will leave it here for now because it is unclear
2544 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2546 WCHAR squished_pc[GUID_SIZE];
2547 WCHAR squished_cc[GUID_SIZE];
2548 UINT rc;
2549 MSICOMPONENT *comp;
2550 HKEY hkey=0,hkey2=0;
2552 if (!package)
2553 return ERROR_INVALID_HANDLE;
2555 /* writes the Component and Features values to the registry */
2557 rc = MSIREG_OpenComponents(&hkey);
2558 if (rc != ERROR_SUCCESS)
2559 goto end;
2561 squash_guid(package->ProductCode,squished_pc);
2562 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2564 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2566 ui_progress(package,2,0,0,0);
2567 if (comp->ComponentId)
2569 MSIRECORD * uirow;
2571 squash_guid(comp->ComponentId,squished_cc);
2573 msi_free(comp->FullKeypath);
2574 comp->FullKeypath = resolve_keypath( package, comp );
2576 /* do the refcounting */
2577 ACTION_RefCountComponent( package, comp );
2579 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2580 debugstr_w(comp->Component),
2581 debugstr_w(squished_cc),
2582 debugstr_w(comp->FullKeypath),
2583 comp->RefCount);
2585 * Write the keypath out if the component is to be registered
2586 * and delete the key if the component is to be deregistered
2588 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2590 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2591 if (rc != ERROR_SUCCESS)
2592 continue;
2594 if (comp->FullKeypath)
2596 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2598 if (comp->Attributes & msidbComponentAttributesPermanent)
2600 static const WCHAR szPermKey[] =
2601 { '0','0','0','0','0','0','0','0','0','0','0','0',
2602 '0','0','0','0','0','0','0','0','0','0','0','0',
2603 '0','0','0','0','0','0','0','0',0};
2605 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2608 RegCloseKey(hkey2);
2610 /* UI stuff */
2611 uirow = MSI_CreateRecord(3);
2612 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2613 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2614 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2615 ui_actiondata(package,szProcessComponents,uirow);
2616 msiobj_release( &uirow->hdr );
2619 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2621 DWORD res;
2623 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2624 if (rc != ERROR_SUCCESS)
2625 continue;
2627 RegDeleteValueW(hkey2,squished_pc);
2629 /* if the key is empty delete it */
2630 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2631 RegCloseKey(hkey2);
2632 if (res == ERROR_NO_MORE_ITEMS)
2633 RegDeleteKeyW(hkey,squished_cc);
2635 /* UI stuff */
2636 uirow = MSI_CreateRecord(2);
2637 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2638 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2639 ui_actiondata(package,szProcessComponents,uirow);
2640 msiobj_release( &uirow->hdr );
2644 end:
2645 RegCloseKey(hkey);
2646 return rc;
2649 typedef struct {
2650 CLSID clsid;
2651 LPWSTR source;
2653 LPWSTR path;
2654 ITypeLib *ptLib;
2655 } typelib_struct;
2657 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2658 LPWSTR lpszName, LONG_PTR lParam)
2660 TLIBATTR *attr;
2661 typelib_struct *tl_struct = (typelib_struct*) lParam;
2662 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2663 int sz;
2664 HRESULT res;
2666 if (!IS_INTRESOURCE(lpszName))
2668 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2669 return TRUE;
2672 sz = strlenW(tl_struct->source)+4;
2673 sz *= sizeof(WCHAR);
2675 if ((INT)lpszName == 1)
2676 tl_struct->path = strdupW(tl_struct->source);
2677 else
2679 tl_struct->path = msi_alloc(sz);
2680 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2683 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2684 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2685 if (!SUCCEEDED(res))
2687 msi_free(tl_struct->path);
2688 tl_struct->path = NULL;
2690 return TRUE;
2693 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2694 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2696 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2697 return FALSE;
2700 msi_free(tl_struct->path);
2701 tl_struct->path = NULL;
2703 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2704 ITypeLib_Release(tl_struct->ptLib);
2706 return TRUE;
2709 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2711 MSIPACKAGE* package = (MSIPACKAGE*)param;
2712 LPCWSTR component;
2713 MSICOMPONENT *comp;
2714 MSIFILE *file;
2715 typelib_struct tl_struct;
2716 HMODULE module;
2717 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2719 component = MSI_RecordGetString(row,3);
2720 comp = get_loaded_component(package,component);
2721 if (!comp)
2722 return ERROR_SUCCESS;
2724 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2726 TRACE("Skipping typelib reg due to disabled component\n");
2728 comp->Action = comp->Installed;
2730 return ERROR_SUCCESS;
2733 comp->Action = INSTALLSTATE_LOCAL;
2735 file = get_loaded_file( package, comp->KeyPath );
2736 if (!file)
2737 return ERROR_SUCCESS;
2739 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2740 if (module)
2742 LPCWSTR guid;
2743 guid = MSI_RecordGetString(row,1);
2744 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2745 tl_struct.source = strdupW( file->TargetPath );
2746 tl_struct.path = NULL;
2748 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2749 (LONG_PTR)&tl_struct);
2751 if (tl_struct.path)
2753 LPWSTR help = NULL;
2754 LPCWSTR helpid;
2755 HRESULT res;
2757 helpid = MSI_RecordGetString(row,6);
2759 if (helpid)
2760 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2761 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2762 msi_free(help);
2764 if (!SUCCEEDED(res))
2765 ERR("Failed to register type library %s\n",
2766 debugstr_w(tl_struct.path));
2767 else
2769 ui_actiondata(package,szRegisterTypeLibraries,row);
2771 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2774 ITypeLib_Release(tl_struct.ptLib);
2775 msi_free(tl_struct.path);
2777 else
2778 ERR("Failed to load type library %s\n",
2779 debugstr_w(tl_struct.source));
2781 FreeLibrary(module);
2782 msi_free(tl_struct.source);
2784 else
2785 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2787 return ERROR_SUCCESS;
2790 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2793 * OK this is a bit confusing.. I am given a _Component key and I believe
2794 * that the file that is being registered as a type library is the "key file
2795 * of that component" which I interpret to mean "The file in the KeyPath of
2796 * that component".
2798 UINT rc;
2799 MSIQUERY * view;
2800 static const WCHAR Query[] =
2801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2802 '`','T','y','p','e','L','i','b','`',0};
2804 if (!package)
2805 return ERROR_INVALID_HANDLE;
2807 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2808 if (rc != ERROR_SUCCESS)
2809 return ERROR_SUCCESS;
2811 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2812 msiobj_release(&view->hdr);
2813 return rc;
2816 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2818 MSIPACKAGE *package = (MSIPACKAGE*)param;
2819 LPWSTR target_file, target_folder;
2820 LPCWSTR buffer;
2821 WCHAR filename[0x100];
2822 DWORD sz;
2823 MSICOMPONENT *comp;
2824 static const WCHAR szlnk[]={'.','l','n','k',0};
2825 IShellLinkW *sl;
2826 IPersistFile *pf;
2827 HRESULT res;
2829 buffer = MSI_RecordGetString(row,4);
2830 comp = get_loaded_component(package,buffer);
2831 if (!comp)
2832 return ERROR_SUCCESS;
2834 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2836 TRACE("Skipping shortcut creation due to disabled component\n");
2838 comp->Action = comp->Installed;
2840 return ERROR_SUCCESS;
2843 comp->Action = INSTALLSTATE_LOCAL;
2845 ui_actiondata(package,szCreateShortcuts,row);
2847 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2848 &IID_IShellLinkW, (LPVOID *) &sl );
2850 if (FAILED(res))
2852 ERR("Is IID_IShellLink\n");
2853 return ERROR_SUCCESS;
2856 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2857 if( FAILED( res ) )
2859 ERR("Is IID_IPersistFile\n");
2860 return ERROR_SUCCESS;
2863 buffer = MSI_RecordGetString(row,2);
2864 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2866 /* may be needed because of a bug somehwere else */
2867 create_full_pathW(target_folder);
2869 sz = 0x100;
2870 MSI_RecordGetStringW(row,3,filename,&sz);
2871 reduce_to_longfilename(filename);
2872 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2873 strcatW(filename,szlnk);
2874 target_file = build_directory_name(2, target_folder, filename);
2875 msi_free(target_folder);
2877 buffer = MSI_RecordGetString(row,5);
2878 if (strchrW(buffer,'['))
2880 LPWSTR deformated;
2881 deformat_string(package,buffer,&deformated);
2882 IShellLinkW_SetPath(sl,deformated);
2883 msi_free(deformated);
2885 else
2887 FIXME("poorly handled shortcut format, advertised shortcut\n");
2888 IShellLinkW_SetPath(sl,comp->FullKeypath);
2891 if (!MSI_RecordIsNull(row,6))
2893 LPWSTR deformated;
2894 buffer = MSI_RecordGetString(row,6);
2895 deformat_string(package,buffer,&deformated);
2896 IShellLinkW_SetArguments(sl,deformated);
2897 msi_free(deformated);
2900 if (!MSI_RecordIsNull(row,7))
2902 buffer = MSI_RecordGetString(row,7);
2903 IShellLinkW_SetDescription(sl,buffer);
2906 if (!MSI_RecordIsNull(row,8))
2907 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2909 if (!MSI_RecordIsNull(row,9))
2911 LPWSTR Path;
2912 INT index;
2914 buffer = MSI_RecordGetString(row,9);
2916 Path = build_icon_path(package,buffer);
2917 index = MSI_RecordGetInteger(row,10);
2919 IShellLinkW_SetIconLocation(sl,Path,index);
2920 msi_free(Path);
2923 if (!MSI_RecordIsNull(row,11))
2924 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2926 if (!MSI_RecordIsNull(row,12))
2928 LPWSTR Path;
2929 buffer = MSI_RecordGetString(row,12);
2930 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2931 IShellLinkW_SetWorkingDirectory(sl,Path);
2932 msi_free(Path);
2935 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2936 IPersistFile_Save(pf,target_file,FALSE);
2938 msi_free(target_file);
2940 IPersistFile_Release( pf );
2941 IShellLinkW_Release( sl );
2943 return ERROR_SUCCESS;
2946 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2948 UINT rc;
2949 HRESULT res;
2950 MSIQUERY * view;
2951 static const WCHAR Query[] =
2952 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2953 '`','S','h','o','r','t','c','u','t','`',0};
2955 if (!package)
2956 return ERROR_INVALID_HANDLE;
2958 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2959 if (rc != ERROR_SUCCESS)
2960 return ERROR_SUCCESS;
2962 res = CoInitialize( NULL );
2963 if (FAILED (res))
2965 ERR("CoInitialize failed\n");
2966 return ERROR_FUNCTION_FAILED;
2969 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2970 msiobj_release(&view->hdr);
2972 CoUninitialize();
2974 return rc;
2977 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2979 MSIPACKAGE* package = (MSIPACKAGE*)param;
2980 HANDLE the_file;
2981 LPWSTR FilePath;
2982 LPCWSTR FileName;
2983 CHAR buffer[1024];
2984 DWORD sz;
2985 UINT rc;
2987 FileName = MSI_RecordGetString(row,1);
2988 if (!FileName)
2990 ERR("Unable to get FileName\n");
2991 return ERROR_SUCCESS;
2994 FilePath = build_icon_path(package,FileName);
2996 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2998 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2999 FILE_ATTRIBUTE_NORMAL, NULL);
3001 if (the_file == INVALID_HANDLE_VALUE)
3003 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3004 msi_free(FilePath);
3005 return ERROR_SUCCESS;
3010 DWORD write;
3011 sz = 1024;
3012 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3013 if (rc != ERROR_SUCCESS)
3015 ERR("Failed to get stream\n");
3016 CloseHandle(the_file);
3017 DeleteFileW(FilePath);
3018 break;
3020 WriteFile(the_file,buffer,sz,&write,NULL);
3021 } while (sz == 1024);
3023 msi_free(FilePath);
3025 CloseHandle(the_file);
3026 return ERROR_SUCCESS;
3030 * 99% of the work done here is only done for
3031 * advertised installs. However this is where the
3032 * Icon table is processed and written out
3033 * so that is what I am going to do here.
3035 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3037 UINT rc;
3038 MSIQUERY * view;
3039 static const WCHAR Query[]=
3040 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3041 '`','I','c','o','n','`',0};
3042 /* for registry stuff */
3043 HKEY hkey=0;
3044 HKEY hukey=0;
3045 static const WCHAR szProductLanguage[] =
3046 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3047 static const WCHAR szARPProductIcon[] =
3048 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3049 static const WCHAR szProductVersion[] =
3050 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3051 DWORD langid;
3052 LPWSTR buffer;
3053 DWORD size;
3054 MSIHANDLE hDb, hSumInfo;
3056 if (!package)
3057 return ERROR_INVALID_HANDLE;
3059 /* write out icon files */
3061 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3062 if (rc == ERROR_SUCCESS)
3064 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3065 msiobj_release(&view->hdr);
3068 /* ok there is a lot more done here but i need to figure out what */
3070 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3071 if (rc != ERROR_SUCCESS)
3072 goto end;
3074 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3075 if (rc != ERROR_SUCCESS)
3076 goto end;
3079 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3080 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3081 msi_free(buffer);
3083 langid = msi_get_property_int( package, szProductLanguage, 0 );
3084 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3086 buffer = msi_dup_property( package, szARPProductIcon );
3087 if (buffer)
3089 LPWSTR path = build_icon_path(package,buffer);
3090 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3091 msi_free( path );
3093 msi_free(buffer);
3095 buffer = msi_dup_property( package, szProductVersion );
3096 if (buffer)
3098 DWORD verdword = build_version_dword(buffer);
3099 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3101 msi_free(buffer);
3103 FIXME("Need to write more keys to the user registry\n");
3105 hDb= alloc_msihandle( &package->db->hdr );
3106 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3107 MsiCloseHandle(hDb);
3108 if (rc == ERROR_SUCCESS)
3110 WCHAR guidbuffer[0x200];
3111 size = 0x200;
3112 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3113 guidbuffer, &size);
3114 if (rc == ERROR_SUCCESS)
3116 WCHAR squashed[GUID_SIZE];
3117 /* for now we only care about the first guid */
3118 LPWSTR ptr = strchrW(guidbuffer,';');
3119 if (ptr) *ptr = 0;
3120 squash_guid(guidbuffer,squashed);
3121 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3123 else
3125 ERR("Unable to query Revision_Number... \n");
3126 rc = ERROR_SUCCESS;
3128 MsiCloseHandle(hSumInfo);
3130 else
3132 ERR("Unable to open Summary Information\n");
3133 rc = ERROR_SUCCESS;
3136 end:
3138 RegCloseKey(hkey);
3139 RegCloseKey(hukey);
3141 return rc;
3144 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3146 MSIPACKAGE *package = (MSIPACKAGE*)param;
3147 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3148 LPWSTR deformated_section, deformated_key, deformated_value;
3149 LPWSTR folder, fullname = NULL;
3150 MSIRECORD * uirow;
3151 INT action;
3152 MSICOMPONENT *comp;
3153 static const WCHAR szWindowsFolder[] =
3154 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3156 component = MSI_RecordGetString(row, 8);
3157 comp = get_loaded_component(package,component);
3159 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3161 TRACE("Skipping ini file due to disabled component %s\n",
3162 debugstr_w(component));
3164 comp->Action = comp->Installed;
3166 return ERROR_SUCCESS;
3169 comp->Action = INSTALLSTATE_LOCAL;
3171 identifier = MSI_RecordGetString(row,1);
3172 filename = MSI_RecordGetString(row,2);
3173 dirproperty = MSI_RecordGetString(row,3);
3174 section = MSI_RecordGetString(row,4);
3175 key = MSI_RecordGetString(row,5);
3176 value = MSI_RecordGetString(row,6);
3177 action = MSI_RecordGetInteger(row,7);
3179 deformat_string(package,section,&deformated_section);
3180 deformat_string(package,key,&deformated_key);
3181 deformat_string(package,value,&deformated_value);
3183 if (dirproperty)
3185 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3186 if (!folder)
3187 folder = msi_dup_property( package, dirproperty );
3189 else
3190 folder = msi_dup_property( package, szWindowsFolder );
3192 if (!folder)
3194 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3195 goto cleanup;
3198 fullname = build_directory_name(2, folder, filename);
3200 if (action == 0)
3202 TRACE("Adding value %s to section %s in %s\n",
3203 debugstr_w(deformated_key), debugstr_w(deformated_section),
3204 debugstr_w(fullname));
3205 WritePrivateProfileStringW(deformated_section, deformated_key,
3206 deformated_value, fullname);
3208 else if (action == 1)
3210 WCHAR returned[10];
3211 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3212 returned, 10, fullname);
3213 if (returned[0] == 0)
3215 TRACE("Adding value %s to section %s in %s\n",
3216 debugstr_w(deformated_key), debugstr_w(deformated_section),
3217 debugstr_w(fullname));
3219 WritePrivateProfileStringW(deformated_section, deformated_key,
3220 deformated_value, fullname);
3223 else if (action == 3)
3224 FIXME("Append to existing section not yet implemented\n");
3226 uirow = MSI_CreateRecord(4);
3227 MSI_RecordSetStringW(uirow,1,identifier);
3228 MSI_RecordSetStringW(uirow,2,deformated_section);
3229 MSI_RecordSetStringW(uirow,3,deformated_key);
3230 MSI_RecordSetStringW(uirow,4,deformated_value);
3231 ui_actiondata(package,szWriteIniValues,uirow);
3232 msiobj_release( &uirow->hdr );
3233 cleanup:
3234 msi_free(fullname);
3235 msi_free(folder);
3236 msi_free(deformated_key);
3237 msi_free(deformated_value);
3238 msi_free(deformated_section);
3239 return ERROR_SUCCESS;
3242 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3244 UINT rc;
3245 MSIQUERY * view;
3246 static const WCHAR ExecSeqQuery[] =
3247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3248 '`','I','n','i','F','i','l','e','`',0};
3250 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3251 if (rc != ERROR_SUCCESS)
3253 TRACE("no IniFile table\n");
3254 return ERROR_SUCCESS;
3257 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3258 msiobj_release(&view->hdr);
3259 return rc;
3262 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3264 MSIPACKAGE *package = (MSIPACKAGE*)param;
3265 LPCWSTR filename;
3266 LPWSTR FullName;
3267 MSIFILE *file;
3268 DWORD len;
3269 static const WCHAR ExeStr[] =
3270 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3271 static const WCHAR close[] = {'\"',0};
3272 STARTUPINFOW si;
3273 PROCESS_INFORMATION info;
3274 BOOL brc;
3276 memset(&si,0,sizeof(STARTUPINFOW));
3278 filename = MSI_RecordGetString(row,1);
3279 file = get_loaded_file( package, filename );
3281 if (!file)
3283 ERR("Unable to find file id %s\n",debugstr_w(filename));
3284 return ERROR_SUCCESS;
3287 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3289 FullName = msi_alloc(len*sizeof(WCHAR));
3290 strcpyW(FullName,ExeStr);
3291 strcatW( FullName, file->TargetPath );
3292 strcatW(FullName,close);
3294 TRACE("Registering %s\n",debugstr_w(FullName));
3295 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3296 &si, &info);
3298 if (brc)
3299 msi_dialog_check_messages(info.hProcess);
3301 msi_free(FullName);
3302 return ERROR_SUCCESS;
3305 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3307 UINT rc;
3308 MSIQUERY * view;
3309 static const WCHAR ExecSeqQuery[] =
3310 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3311 '`','S','e','l','f','R','e','g','`',0};
3313 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3314 if (rc != ERROR_SUCCESS)
3316 TRACE("no SelfReg table\n");
3317 return ERROR_SUCCESS;
3320 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3321 msiobj_release(&view->hdr);
3323 return ERROR_SUCCESS;
3326 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3328 MSIFEATURE *feature;
3329 UINT rc;
3330 HKEY hkey=0;
3331 HKEY hukey=0;
3333 if (!package)
3334 return ERROR_INVALID_HANDLE;
3336 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3337 if (rc != ERROR_SUCCESS)
3338 goto end;
3340 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3341 if (rc != ERROR_SUCCESS)
3342 goto end;
3344 /* here the guids are base 85 encoded */
3345 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3347 ComponentList *cl;
3348 LPWSTR data = NULL;
3349 GUID clsid;
3350 INT size;
3351 BOOL absent = FALSE;
3353 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3354 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3355 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3356 absent = TRUE;
3358 size = 1;
3359 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3361 size += 21;
3363 if (feature->Feature_Parent)
3364 size += strlenW( feature->Feature_Parent )+2;
3366 data = msi_alloc(size * sizeof(WCHAR));
3368 data[0] = 0;
3369 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3371 MSICOMPONENT* component = cl->component;
3372 WCHAR buf[21];
3374 memset(buf,0,sizeof(buf));
3375 if (component->ComponentId)
3377 TRACE("From %s\n",debugstr_w(component->ComponentId));
3378 CLSIDFromString(component->ComponentId, &clsid);
3379 encode_base85_guid(&clsid,buf);
3380 TRACE("to %s\n",debugstr_w(buf));
3381 strcatW(data,buf);
3384 if (feature->Feature_Parent)
3386 static const WCHAR sep[] = {'\2',0};
3387 strcatW(data,sep);
3388 strcatW(data,feature->Feature_Parent);
3391 msi_reg_set_val_str( hkey, feature->Feature, data );
3392 msi_free(data);
3394 size = 0;
3395 if (feature->Feature_Parent)
3396 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3397 if (!absent)
3399 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3400 (LPBYTE)feature->Feature_Parent,size);
3402 else
3404 size += 2*sizeof(WCHAR);
3405 data = msi_alloc(size);
3406 data[0] = 0x6;
3407 data[1] = 0;
3408 if (feature->Feature_Parent)
3409 strcpyW( &data[1], feature->Feature_Parent );
3410 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3411 (LPBYTE)data,size);
3412 msi_free(data);
3416 end:
3417 RegCloseKey(hkey);
3418 RegCloseKey(hukey);
3419 return rc;
3422 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3424 static const WCHAR installerPathFmt[] = {
3425 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3426 static const WCHAR fmt[] = {
3427 '%','s','\\',
3428 'I','n','s','t','a','l','l','e','r','\\',
3429 '%','x','.','m','s','i',0};
3430 static const WCHAR szOriginalDatabase[] =
3431 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3432 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3433 INT num, start;
3434 LPWSTR msiFilePath;
3435 BOOL r;
3437 /* copy the package locally */
3438 num = GetTickCount() & 0xffff;
3439 if (!num)
3440 num = 1;
3441 start = num;
3442 GetWindowsDirectoryW( windir, MAX_PATH );
3443 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3446 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3447 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3448 if (handle != INVALID_HANDLE_VALUE)
3450 CloseHandle(handle);
3451 break;
3453 if (GetLastError() != ERROR_FILE_EXISTS &&
3454 GetLastError() != ERROR_SHARING_VIOLATION)
3455 break;
3456 if (!(++num & 0xffff)) num = 1;
3457 sprintfW(packagefile,fmt,num);
3458 } while (num != start);
3460 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3461 create_full_pathW(path);
3463 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3465 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3466 r = CopyFileW( msiFilePath, packagefile, FALSE);
3467 msi_free( msiFilePath );
3469 if (!r)
3471 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3472 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3473 return ERROR_FUNCTION_FAILED;
3476 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3477 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3478 return ERROR_SUCCESS;
3481 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3483 LPWSTR prop, val, key;
3484 static const LPCSTR propval[] = {
3485 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3486 "ARPCONTACT", "Contact",
3487 "ARPCOMMENTS", "Comments",
3488 "ProductName", "DisplayName",
3489 "ProductVersion", "DisplayVersion",
3490 "ARPHELPLINK", "HelpLink",
3491 "ARPHELPTELEPHONE", "HelpTelephone",
3492 "ARPINSTALLLOCATION", "InstallLocation",
3493 "SourceDir", "InstallSource",
3494 "Manufacturer", "Publisher",
3495 "ARPREADME", "Readme",
3496 "ARPSIZE", "Size",
3497 "ARPURLINFOABOUT", "URLInfoAbout",
3498 "ARPURLUPDATEINFO", "URLUpdateInfo",
3499 NULL,
3501 const LPCSTR *p = propval;
3503 while( *p )
3505 prop = strdupAtoW( *p++ );
3506 key = strdupAtoW( *p++ );
3507 val = msi_dup_property( package, prop );
3508 msi_reg_set_val_str( hkey, key, val );
3509 msi_free(val);
3510 msi_free(key);
3511 msi_free(prop);
3513 return ERROR_SUCCESS;
3516 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3518 HKEY hkey=0;
3519 LPWSTR buffer = NULL;
3520 UINT rc;
3521 DWORD size, langid;
3522 static const WCHAR szWindowsInstaller[] =
3523 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3524 static const WCHAR szUpgradeCode[] =
3525 {'U','p','g','r','a','d','e','C','o','d','e',0};
3526 static const WCHAR modpath_fmt[] =
3527 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3528 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3529 static const WCHAR szModifyPath[] =
3530 {'M','o','d','i','f','y','P','a','t','h',0};
3531 static const WCHAR szUninstallString[] =
3532 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3533 static const WCHAR szEstimatedSize[] =
3534 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3535 static const WCHAR szProductLanguage[] =
3536 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3537 static const WCHAR szProductVersion[] =
3538 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3540 SYSTEMTIME systime;
3541 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3542 LPWSTR upgrade_code;
3543 WCHAR szDate[9];
3545 if (!package)
3546 return ERROR_INVALID_HANDLE;
3548 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3549 if (rc != ERROR_SUCCESS)
3550 return rc;
3552 /* dump all the info i can grab */
3553 FIXME("Flesh out more information \n");
3555 msi_write_uninstall_property_vals( package, hkey );
3557 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3559 msi_make_package_local( package, hkey );
3561 /* do ModifyPath and UninstallString */
3562 size = deformat_string(package,modpath_fmt,&buffer);
3563 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3564 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3565 msi_free(buffer);
3567 FIXME("Write real Estimated Size when we have it\n");
3568 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3570 GetLocalTime(&systime);
3571 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3572 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3574 langid = msi_get_property_int( package, szProductLanguage, 0 );
3575 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3577 buffer = msi_dup_property( package, szProductVersion );
3578 if (buffer)
3580 DWORD verdword = build_version_dword(buffer);
3582 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3583 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3584 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3586 msi_free(buffer);
3588 /* Handle Upgrade Codes */
3589 upgrade_code = msi_dup_property( package, szUpgradeCode );
3590 if (upgrade_code)
3592 HKEY hkey2;
3593 WCHAR squashed[33];
3594 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3595 squash_guid(package->ProductCode,squashed);
3596 msi_reg_set_val_str( hkey2, squashed, NULL );
3597 RegCloseKey(hkey2);
3598 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3599 squash_guid(package->ProductCode,squashed);
3600 msi_reg_set_val_str( hkey2, squashed, NULL );
3601 RegCloseKey(hkey2);
3603 msi_free(upgrade_code);
3606 RegCloseKey(hkey);
3608 return ERROR_SUCCESS;
3611 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3613 UINT rc;
3615 if (!package)
3616 return ERROR_INVALID_HANDLE;
3618 rc = execute_script(package,INSTALL_SCRIPT);
3620 return rc;
3623 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3625 UINT rc;
3627 if (!package)
3628 return ERROR_INVALID_HANDLE;
3630 /* turn off scheduleing */
3631 package->script->CurrentlyScripting= FALSE;
3633 /* first do the same as an InstallExecute */
3634 rc = ACTION_InstallExecute(package);
3635 if (rc != ERROR_SUCCESS)
3636 return rc;
3638 /* then handle Commit Actions */
3639 rc = execute_script(package,COMMIT_SCRIPT);
3641 return rc;
3644 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3646 static const WCHAR RunOnce[] = {
3647 'S','o','f','t','w','a','r','e','\\',
3648 'M','i','c','r','o','s','o','f','t','\\',
3649 'W','i','n','d','o','w','s','\\',
3650 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3651 'R','u','n','O','n','c','e',0};
3652 static const WCHAR InstallRunOnce[] = {
3653 'S','o','f','t','w','a','r','e','\\',
3654 'M','i','c','r','o','s','o','f','t','\\',
3655 'W','i','n','d','o','w','s','\\',
3656 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3657 'I','n','s','t','a','l','l','e','r','\\',
3658 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3660 static const WCHAR msiexec_fmt[] = {
3661 '%','s',
3662 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3663 '\"','%','s','\"',0};
3664 static const WCHAR install_fmt[] = {
3665 '/','I',' ','\"','%','s','\"',' ',
3666 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3667 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3668 WCHAR buffer[256], sysdir[MAX_PATH];
3669 HKEY hkey;
3670 WCHAR squished_pc[100];
3672 if (!package)
3673 return ERROR_INVALID_HANDLE;
3675 squash_guid(package->ProductCode,squished_pc);
3677 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3678 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3679 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3680 squished_pc);
3682 msi_reg_set_val_str( hkey, squished_pc, buffer );
3683 RegCloseKey(hkey);
3685 TRACE("Reboot command %s\n",debugstr_w(buffer));
3687 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3688 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3690 msi_reg_set_val_str( hkey, squished_pc, buffer );
3691 RegCloseKey(hkey);
3693 return ERROR_INSTALL_SUSPEND;
3696 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3698 DWORD attrib;
3699 UINT rc;
3701 * we are currently doing what should be done here in the top level Install
3702 * however for Adminastrative and uninstalls this step will be needed
3704 if (!package->PackagePath)
3705 return ERROR_SUCCESS;
3707 attrib = GetFileAttributesW(package->PackagePath);
3708 if (attrib == INVALID_FILE_ATTRIBUTES)
3710 LPWSTR prompt;
3711 LPWSTR msg;
3712 DWORD size = 0;
3714 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3715 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3716 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3717 if (rc == ERROR_MORE_DATA)
3719 prompt = msi_alloc(size * sizeof(WCHAR));
3720 MsiSourceListGetInfoW(package->ProductCode, NULL,
3721 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3722 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3724 else
3725 prompt = strdupW(package->PackagePath);
3727 msg = generate_error_string(package,1302,1,prompt);
3728 while(attrib == INVALID_FILE_ATTRIBUTES)
3730 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3731 if (rc == IDCANCEL)
3733 rc = ERROR_INSTALL_USEREXIT;
3734 break;
3736 attrib = GetFileAttributesW(package->PackagePath);
3738 msi_free(prompt);
3739 rc = ERROR_SUCCESS;
3741 else
3742 return ERROR_SUCCESS;
3744 return rc;
3747 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3749 HKEY hkey=0;
3750 LPWSTR buffer;
3751 LPWSTR productid;
3752 UINT rc,i;
3754 static const WCHAR szPropKeys[][80] =
3756 {'P','r','o','d','u','c','t','I','D',0},
3757 {'U','S','E','R','N','A','M','E',0},
3758 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3759 {0},
3762 static const WCHAR szRegKeys[][80] =
3764 {'P','r','o','d','u','c','t','I','D',0},
3765 {'R','e','g','O','w','n','e','r',0},
3766 {'R','e','g','C','o','m','p','a','n','y',0},
3767 {0},
3770 if (!package)
3771 return ERROR_INVALID_HANDLE;
3773 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3774 if (!productid)
3775 return ERROR_SUCCESS;
3777 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3778 if (rc != ERROR_SUCCESS)
3779 goto end;
3781 for( i = 0; szPropKeys[i][0]; i++ )
3783 buffer = msi_dup_property( package, szPropKeys[i] );
3784 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3785 msi_free( buffer );
3788 end:
3789 msi_free(productid);
3790 RegCloseKey(hkey);
3792 return ERROR_SUCCESS;
3796 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3798 UINT rc;
3800 package->script->InWhatSequence |= SEQUENCE_EXEC;
3801 rc = ACTION_ProcessExecSequence(package,FALSE);
3802 return rc;
3807 * Code based off of code located here
3808 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3810 * Using string index 4 (full font name) instead of 1 (family name)
3812 static LPWSTR load_ttfname_from(LPCWSTR filename)
3814 HANDLE handle;
3815 LPWSTR ret = NULL;
3816 int i;
3818 typedef struct _tagTT_OFFSET_TABLE{
3819 USHORT uMajorVersion;
3820 USHORT uMinorVersion;
3821 USHORT uNumOfTables;
3822 USHORT uSearchRange;
3823 USHORT uEntrySelector;
3824 USHORT uRangeShift;
3825 }TT_OFFSET_TABLE;
3827 typedef struct _tagTT_TABLE_DIRECTORY{
3828 char szTag[4]; /* table name */
3829 ULONG uCheckSum; /* Check sum */
3830 ULONG uOffset; /* Offset from beginning of file */
3831 ULONG uLength; /* length of the table in bytes */
3832 }TT_TABLE_DIRECTORY;
3834 typedef struct _tagTT_NAME_TABLE_HEADER{
3835 USHORT uFSelector; /* format selector. Always 0 */
3836 USHORT uNRCount; /* Name Records count */
3837 USHORT uStorageOffset; /* Offset for strings storage,
3838 * from start of the table */
3839 }TT_NAME_TABLE_HEADER;
3841 typedef struct _tagTT_NAME_RECORD{
3842 USHORT uPlatformID;
3843 USHORT uEncodingID;
3844 USHORT uLanguageID;
3845 USHORT uNameID;
3846 USHORT uStringLength;
3847 USHORT uStringOffset; /* from start of storage area */
3848 }TT_NAME_RECORD;
3850 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3851 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3853 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3854 FILE_ATTRIBUTE_NORMAL, 0 );
3855 if (handle != INVALID_HANDLE_VALUE)
3857 TT_TABLE_DIRECTORY tblDir;
3858 BOOL bFound = FALSE;
3859 TT_OFFSET_TABLE ttOffsetTable;
3860 DWORD dwRead;
3862 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3863 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3864 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3865 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3867 if (ttOffsetTable.uMajorVersion != 1 ||
3868 ttOffsetTable.uMinorVersion != 0)
3869 return NULL;
3871 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3873 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3874 if (strncmp(tblDir.szTag,"name",4)==0)
3876 bFound = TRUE;
3877 tblDir.uLength = SWAPLONG(tblDir.uLength);
3878 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3879 break;
3883 if (bFound)
3885 TT_NAME_TABLE_HEADER ttNTHeader;
3886 TT_NAME_RECORD ttRecord;
3888 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3889 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3890 &dwRead,NULL);
3892 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3893 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3894 bFound = FALSE;
3895 for(i=0; i<ttNTHeader.uNRCount; i++)
3897 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3898 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3899 /* 4 is the Full Font Name */
3900 if(ttRecord.uNameID == 4)
3902 int nPos;
3903 LPSTR buf;
3904 static LPCSTR tt = " (TrueType)";
3906 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3907 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3908 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3909 SetFilePointer(handle, tblDir.uOffset +
3910 ttRecord.uStringOffset +
3911 ttNTHeader.uStorageOffset,
3912 NULL, FILE_BEGIN);
3913 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3914 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3915 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3916 if (strlen(buf) > 0)
3918 strcat(buf,tt);
3919 ret = strdupAtoW(buf);
3920 msi_free(buf);
3921 break;
3924 msi_free(buf);
3925 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3929 CloseHandle(handle);
3931 else
3932 ERR("Unable to open font file %s\n", debugstr_w(filename));
3934 TRACE("Returning fontname %s\n",debugstr_w(ret));
3935 return ret;
3938 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3940 MSIPACKAGE *package = (MSIPACKAGE*)param;
3941 LPWSTR name;
3942 LPCWSTR filename;
3943 MSIFILE *file;
3944 static const WCHAR regfont1[] =
3945 {'S','o','f','t','w','a','r','e','\\',
3946 'M','i','c','r','o','s','o','f','t','\\',
3947 'W','i','n','d','o','w','s',' ','N','T','\\',
3948 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3949 'F','o','n','t','s',0};
3950 static const WCHAR regfont2[] =
3951 {'S','o','f','t','w','a','r','e','\\',
3952 'M','i','c','r','o','s','o','f','t','\\',
3953 'W','i','n','d','o','w','s','\\',
3954 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3955 'F','o','n','t','s',0};
3956 HKEY hkey1;
3957 HKEY hkey2;
3959 filename = MSI_RecordGetString( row, 1 );
3960 file = get_loaded_file( package, filename );
3961 if (!file)
3963 ERR("Unable to load file\n");
3964 return ERROR_SUCCESS;
3967 /* check to make sure that component is installed */
3968 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3970 TRACE("Skipping: Component not scheduled for install\n");
3971 return ERROR_SUCCESS;
3974 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3975 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3977 if (MSI_RecordIsNull(row,2))
3978 name = load_ttfname_from( file->TargetPath );
3979 else
3980 name = msi_dup_record_field(row,2);
3982 if (name)
3984 msi_reg_set_val_str( hkey1, name, file->FileName );
3985 msi_reg_set_val_str( hkey2, name, file->FileName );
3988 msi_free(name);
3989 RegCloseKey(hkey1);
3990 RegCloseKey(hkey2);
3991 return ERROR_SUCCESS;
3994 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
3996 UINT rc;
3997 MSIQUERY * view;
3998 static const WCHAR ExecSeqQuery[] =
3999 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4000 '`','F','o','n','t','`',0};
4002 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4003 if (rc != ERROR_SUCCESS)
4005 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4006 return ERROR_SUCCESS;
4009 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4010 msiobj_release(&view->hdr);
4012 return ERROR_SUCCESS;
4015 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4017 MSIPACKAGE *package = (MSIPACKAGE*)param;
4018 LPCWSTR compgroupid=NULL;
4019 LPCWSTR feature=NULL;
4020 LPCWSTR text = NULL;
4021 LPCWSTR qualifier = NULL;
4022 LPCWSTR component = NULL;
4023 LPWSTR advertise = NULL;
4024 LPWSTR output = NULL;
4025 HKEY hkey;
4026 UINT rc = ERROR_SUCCESS;
4027 MSICOMPONENT *comp;
4028 DWORD sz = 0;
4030 component = MSI_RecordGetString(rec,3);
4031 comp = get_loaded_component(package,component);
4033 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4034 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4035 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4037 TRACE("Skipping: Component %s not scheduled for install\n",
4038 debugstr_w(component));
4040 return ERROR_SUCCESS;
4043 compgroupid = MSI_RecordGetString(rec,1);
4045 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4046 if (rc != ERROR_SUCCESS)
4047 goto end;
4049 text = MSI_RecordGetString(rec,4);
4050 qualifier = MSI_RecordGetString(rec,2);
4051 feature = MSI_RecordGetString(rec,5);
4053 advertise = create_component_advertise_string(package, comp, feature);
4055 sz = strlenW(advertise);
4057 if (text)
4058 sz += lstrlenW(text);
4060 sz+=3;
4061 sz *= sizeof(WCHAR);
4063 output = msi_alloc(sz);
4064 memset(output,0,sz);
4065 strcpyW(output,advertise);
4066 msi_free(advertise);
4068 if (text)
4069 strcatW(output,text);
4071 msi_reg_set_val_multi_str( hkey, qualifier, output );
4073 end:
4074 RegCloseKey(hkey);
4075 msi_free(output);
4077 return rc;
4081 * At present I am ignorning the advertised components part of this and only
4082 * focusing on the qualified component sets
4084 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4086 UINT rc;
4087 MSIQUERY * view;
4088 static const WCHAR ExecSeqQuery[] =
4089 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4090 '`','P','u','b','l','i','s','h',
4091 'C','o','m','p','o','n','e','n','t','`',0};
4093 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4094 if (rc != ERROR_SUCCESS)
4095 return ERROR_SUCCESS;
4097 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4098 msiobj_release(&view->hdr);
4100 return rc;
4103 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4104 LPCSTR action, LPCWSTR table )
4106 static const WCHAR query[] = {
4107 'S','E','L','E','C','T',' ','*',' ',
4108 'F','R','O','M',' ','`','%','s','`',0 };
4109 MSIQUERY *view = NULL;
4110 DWORD count = 0;
4111 UINT r;
4113 r = MSI_OpenQuery( package->db, &view, query, table );
4114 if (r == ERROR_SUCCESS)
4116 r = MSI_IterateRecords(view, &count, NULL, package);
4117 msiobj_release(&view->hdr);
4120 if (count)
4121 FIXME("%s -> %lu ignored %s table values\n",
4122 action, count, debugstr_w(table));
4124 return ERROR_SUCCESS;
4127 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4129 static const WCHAR table[] =
4130 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4131 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4134 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4136 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4137 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4140 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4142 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4143 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4146 static UINT ACTION_BindImage( MSIPACKAGE *package )
4148 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4149 return msi_unimplemented_action_stub( package, "BindImage", table );
4152 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4154 static const WCHAR table[] = {
4155 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4156 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4159 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4161 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4162 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4165 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4167 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4168 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4171 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4173 static const WCHAR table[] = {
4174 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4175 return msi_unimplemented_action_stub( package, "InstallServices", table );
4178 static UINT ACTION_StartServices( MSIPACKAGE *package )
4180 static const WCHAR table[] = {
4181 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4182 return msi_unimplemented_action_stub( package, "StartServices", table );
4185 static UINT ACTION_StopServices( MSIPACKAGE *package )
4187 static const WCHAR table[] = {
4188 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4189 return msi_unimplemented_action_stub( package, "StopServices", table );
4192 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4194 static const WCHAR table[] = {
4195 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4196 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4199 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4201 static const WCHAR table[] = {
4202 'E','n','v','i','r','o','n','m','e','n','t',0 };
4203 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4206 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4208 static const WCHAR table[] = {
4209 'E','n','v','i','r','o','n','m','e','n','t',0 };
4210 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4213 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4215 static const WCHAR table[] = {
4216 'M','s','i','A','s','s','e','m','b','l','y',0 };
4217 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4220 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4222 static const WCHAR table[] = {
4223 'M','s','i','A','s','s','e','m','b','l','y',0 };
4224 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4227 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4229 static const WCHAR table[] = { 'F','o','n','t',0 };
4230 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4233 static struct _actions StandardActions[] = {
4234 { szAllocateRegistrySpace, NULL},
4235 { szAppSearch, ACTION_AppSearch },
4236 { szBindImage, ACTION_BindImage },
4237 { szCCPSearch, NULL},
4238 { szCostFinalize, ACTION_CostFinalize },
4239 { szCostInitialize, ACTION_CostInitialize },
4240 { szCreateFolders, ACTION_CreateFolders },
4241 { szCreateShortcuts, ACTION_CreateShortcuts },
4242 { szDeleteServices, ACTION_DeleteServices },
4243 { szDisableRollback, NULL},
4244 { szDuplicateFiles, ACTION_DuplicateFiles },
4245 { szExecuteAction, ACTION_ExecuteAction },
4246 { szFileCost, ACTION_FileCost },
4247 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4248 { szForceReboot, ACTION_ForceReboot },
4249 { szInstallAdminPackage, NULL},
4250 { szInstallExecute, ACTION_InstallExecute },
4251 { szInstallExecuteAgain, ACTION_InstallExecute },
4252 { szInstallFiles, ACTION_InstallFiles},
4253 { szInstallFinalize, ACTION_InstallFinalize },
4254 { szInstallInitialize, ACTION_InstallInitialize },
4255 { szInstallSFPCatalogFile, NULL},
4256 { szInstallValidate, ACTION_InstallValidate },
4257 { szIsolateComponents, ACTION_IsolateComponents },
4258 { szLaunchConditions, ACTION_LaunchConditions },
4259 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4260 { szMoveFiles, ACTION_MoveFiles },
4261 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4262 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4263 { szInstallODBC, NULL},
4264 { szInstallServices, ACTION_InstallServices },
4265 { szPatchFiles, ACTION_PatchFiles },
4266 { szProcessComponents, ACTION_ProcessComponents },
4267 { szPublishComponents, ACTION_PublishComponents },
4268 { szPublishFeatures, ACTION_PublishFeatures },
4269 { szPublishProduct, ACTION_PublishProduct },
4270 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4271 { szRegisterComPlus, NULL},
4272 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4273 { szRegisterFonts, ACTION_RegisterFonts },
4274 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4275 { szRegisterProduct, ACTION_RegisterProduct },
4276 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4277 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4278 { szRegisterUser, ACTION_RegisterUser},
4279 { szRemoveDuplicateFiles, NULL},
4280 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4281 { szRemoveExistingProducts, NULL},
4282 { szRemoveFiles, NULL},
4283 { szRemoveFolders, NULL},
4284 { szRemoveIniValues, ACTION_RemoveIniValues },
4285 { szRemoveODBC, NULL},
4286 { szRemoveRegistryValues, NULL},
4287 { szRemoveShortcuts, NULL},
4288 { szResolveSource, ACTION_ResolveSource},
4289 { szRMCCPSearch, NULL},
4290 { szScheduleReboot, NULL},
4291 { szSelfRegModules, ACTION_SelfRegModules },
4292 { szSelfUnregModules, ACTION_SelfUnregModules },
4293 { szSetODBCFolders, NULL},
4294 { szStartServices, ACTION_StartServices },
4295 { szStopServices, ACTION_StopServices },
4296 { szUnpublishComponents, NULL},
4297 { szUnpublishFeatures, NULL},
4298 { szUnregisterClassInfo, NULL},
4299 { szUnregisterComPlus, NULL},
4300 { szUnregisterExtensionInfo, NULL},
4301 { szUnregisterFonts, ACTION_UnregisterFonts },
4302 { szUnregisterMIMEInfo, NULL},
4303 { szUnregisterProgIdInfo, NULL},
4304 { szUnregisterTypeLibraries, NULL},
4305 { szValidateProductID, NULL},
4306 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4307 { szWriteIniValues, ACTION_WriteIniValues },
4308 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4309 { NULL, NULL},