msi: Eliminate a fixed length buffer.
[wine/multimedia.git] / dlls / msi / action.c
blob61dd099e2bb130a787e614f3887463e4aaef0500
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
31 #define COBJMACROS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "wine/debug.h"
38 #include "msidefs.h"
39 #include "msipriv.h"
40 #include "winuser.h"
41 #include "shlobj.h"
42 #include "wine/unicode.h"
43 #include "winver.h"
44 #include "action.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 * Prototypes
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238 struct _actions {
239 LPCWSTR action;
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
247 * helper functions
248 ********************************************************/
250 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
252 static const WCHAR szActionText[] =
253 {'A','c','t','i','o','n','T','e','x','t',0};
254 MSIRECORD *row;
256 row = MSI_CreateRecord(1);
257 MSI_RecordSetStringW(row,1,action);
258 ControlEvent_FireSubscribedEvent(package,szActionText, row);
259 msiobj_release(&row->hdr);
262 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
264 static const WCHAR template_s[]=
265 {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
266 '.',0};
267 static const WCHAR format[] =
268 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
269 static const WCHAR Query_t[] =
270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
271 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
272 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
273 ' ','\'','%','s','\'',0};
274 WCHAR message[1024];
275 WCHAR timet[0x100];
276 MSIRECORD * row = 0;
277 LPCWSTR ActionText;
278 LPWSTR deformated;
280 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
282 row = MSI_QueryGetRecord( package->db, Query_t, action );
283 if (!row)
284 return;
286 ActionText = MSI_RecordGetString(row,2);
287 deformat_string(package, ActionText, &deformated);
289 sprintfW(message,template_s,timet,action,deformated);
290 ce_actiontext(package, deformated);
291 msiobj_release(&row->hdr);
293 row = MSI_CreateRecord(1);
294 MSI_RecordSetStringW(row,1,message);
296 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
297 msiobj_release(&row->hdr);
298 msi_free(deformated);
301 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
302 UINT rc)
304 MSIRECORD * row;
305 static const WCHAR template_s[]=
306 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
307 '%','s', '.',0};
308 static const WCHAR template_e[]=
309 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
310 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
311 '%','i','.',0};
312 static const WCHAR format[] =
313 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
314 WCHAR message[1024];
315 WCHAR timet[0x100];
317 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
318 if (start)
319 sprintfW(message,template_s,timet,action);
320 else
321 sprintfW(message,template_e,timet,action,rc);
323 row = MSI_CreateRecord(1);
324 MSI_RecordSetStringW(row,1,message);
326 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
327 msiobj_release(&row->hdr);
330 static int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
332 LPWSTR str = msi_dup_property( package, prop );
333 int val = str ? atoiW( str ) : def;
334 msi_free( str );
335 return val;
338 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
340 LPCWSTR ptr,ptr2;
341 BOOL quote;
342 DWORD len;
343 LPWSTR prop = NULL, val = NULL;
345 if (!szCommandLine)
346 return ERROR_SUCCESS;
348 ptr = szCommandLine;
350 while (*ptr)
352 if (*ptr==' ')
354 ptr++;
355 continue;
358 TRACE("Looking at %s\n",debugstr_w(ptr));
360 ptr2 = strchrW(ptr,'=');
361 if (!ptr2)
363 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
364 break;
367 quote = FALSE;
369 len = ptr2-ptr;
370 prop = msi_alloc((len+1)*sizeof(WCHAR));
371 memcpy(prop,ptr,len*sizeof(WCHAR));
372 prop[len]=0;
373 ptr2++;
375 len = 0;
376 ptr = ptr2;
377 while (*ptr && (quote || (!quote && *ptr!=' ')))
379 if (*ptr == '"')
380 quote = !quote;
381 ptr++;
382 len++;
385 if (*ptr2=='"')
387 ptr2++;
388 len -= 2;
390 val = msi_alloc((len+1)*sizeof(WCHAR));
391 memcpy(val,ptr2,len*sizeof(WCHAR));
392 val[len] = 0;
394 if (lstrlenW(prop) > 0)
396 TRACE("Found commandline property (%s) = (%s)\n",
397 debugstr_w(prop), debugstr_w(val));
398 MSI_SetPropertyW(package,prop,val);
400 msi_free(val);
401 msi_free(prop);
404 return ERROR_SUCCESS;
408 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
410 LPWSTR p, *ret = NULL;
411 UINT count = 0;
413 if (!str)
414 return ret;
416 /* count the number of substrings */
417 for ( p = (LPWSTR)str, count = 0; p; count++ )
419 p = strchrW( p, sep );
420 if (p)
421 p++;
424 /* allocate space for an array of substring pointers and the substrings */
425 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
426 (lstrlenW(str)+1) * sizeof(WCHAR) );
427 if (!ret)
428 return ret;
430 /* copy the string and set the pointers */
431 p = (LPWSTR) &ret[count+1];
432 lstrcpyW( p, str );
433 for( count = 0; (ret[count] = p); count++ )
435 p = strchrW( p, sep );
436 if (p)
437 *p++ = 0;
440 return ret;
443 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
444 MSIDATABASE *patch_db, LPCWSTR name )
446 UINT ret = ERROR_FUNCTION_FAILED;
447 IStorage *stg = NULL;
448 HRESULT r;
450 TRACE("%p %s\n", package, debugstr_w(name) );
452 if (*name++ != ':')
454 ERR("expected a colon in %s\n", debugstr_w(name));
455 return ERROR_FUNCTION_FAILED;
458 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
459 if (SUCCEEDED(r))
461 ret = msi_table_apply_transform( package->db, stg );
462 IStorage_Release( stg );
463 ret = ERROR_SUCCESS;
465 else
466 ERR("failed to open substorage %s\n", debugstr_w(name));
468 return ret;
471 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
473 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
474 LPWSTR guid_list, *guids, product_id;
475 UINT i, ret = ERROR_FUNCTION_FAILED;
477 product_id = msi_dup_property( package, szProdID );
478 if (!product_id)
480 /* FIXME: the property ProductID should be written into the DB somewhere */
481 ERR("no product ID to check\n");
482 return ERROR_SUCCESS;
485 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
486 guids = msi_split_string( guid_list, ';' );
487 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
489 if (!lstrcmpW( guids[i], product_id ))
490 ret = ERROR_SUCCESS;
492 msi_free( guids );
493 msi_free( guid_list );
494 msi_free( product_id );
496 return ret;
499 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
501 MSISUMMARYINFO *si;
502 LPWSTR str, *substorage;
503 UINT i, r = ERROR_SUCCESS;
505 si = MSI_GetSummaryInformationW( patch_db, 0 );
506 if (!si)
507 return ERROR_FUNCTION_FAILED;
509 msi_check_patch_applicable( package, si );
511 /* enumerate the substorage */
512 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
513 substorage = msi_split_string( str, ';' );
514 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
515 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
516 msi_free( substorage );
517 msi_free( str );
519 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
521 msiobj_release( &si->hdr );
523 return r;
526 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
528 MSIDATABASE *patch_db = NULL;
529 UINT r;
531 TRACE("%p %s\n", package, debugstr_w( file ) );
533 /* FIXME:
534 * We probably want to make sure we only open a patch collection here.
535 * Patch collections (.msp) and databases (.msi) have different GUIDs
536 * but currently MSI_OpenDatabaseW will accept both.
538 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
539 if ( r != ERROR_SUCCESS )
541 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
542 return r;
545 msi_parse_patch_summary( package, patch_db );
546 msiobj_release( &patch_db->hdr );
548 return ERROR_SUCCESS;
551 /* get the PATCH property, and apply all the patches it specifies */
552 static UINT msi_apply_patches( MSIPACKAGE *package )
554 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
555 LPWSTR patch_list, *patches;
556 UINT i, r = ERROR_SUCCESS;
558 patch_list = msi_dup_property( package, szPatch );
560 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
562 patches = msi_split_string( patch_list, ';' );
563 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
564 r = msi_apply_patch_package( package, patches[i] );
566 msi_free( patches );
567 msi_free( patch_list );
569 return r;
572 static UINT msi_apply_transforms( MSIPACKAGE *package )
574 static const WCHAR szTransforms[] = {
575 'T','R','A','N','S','F','O','R','M','S',0 };
576 LPWSTR xform_list, *xforms;
577 UINT i, r = ERROR_SUCCESS;
579 xform_list = msi_dup_property( package, szTransforms );
580 xforms = msi_split_string( xform_list, ';' );
582 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
584 if (xforms[i][0] == ':')
585 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
586 else
587 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
590 msi_free( xforms );
591 msi_free( xform_list );
593 return r;
596 /****************************************************
597 * TOP level entry points
598 *****************************************************/
600 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
601 LPCWSTR szCommandLine )
603 UINT rc;
604 BOOL ui = FALSE;
605 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
606 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
607 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
609 MSI_SetPropertyW(package, szAction, szInstall);
611 package->script = msi_alloc(sizeof(MSISCRIPT));
612 memset(package->script,0,sizeof(MSISCRIPT));
614 package->script->InWhatSequence = SEQUENCE_INSTALL;
616 if (szPackagePath)
618 LPWSTR p, check, path;
620 package->PackagePath = strdupW(szPackagePath);
621 path = strdupW(szPackagePath);
622 p = strrchrW(path,'\\');
623 if (p)
625 p++;
626 *p=0;
628 else
630 msi_free(path);
631 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
632 GetCurrentDirectoryW(MAX_PATH,path);
633 strcatW(path,cszbs);
636 check = msi_dup_property( package, cszSourceDir );
637 if (!check)
638 MSI_SetPropertyW(package, cszSourceDir, path);
639 msi_free(check);
640 msi_free(path);
643 msi_parse_command_line( package, szCommandLine );
645 msi_apply_transforms( package );
646 msi_apply_patches( package );
648 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
650 package->script->InWhatSequence |= SEQUENCE_UI;
651 rc = ACTION_ProcessUISequence(package);
652 ui = TRUE;
653 if (rc == ERROR_SUCCESS)
655 package->script->InWhatSequence |= SEQUENCE_EXEC;
656 rc = ACTION_ProcessExecSequence(package,TRUE);
659 else
660 rc = ACTION_ProcessExecSequence(package,FALSE);
662 if (rc == -1)
664 /* install was halted but should be considered a success */
665 rc = ERROR_SUCCESS;
668 package->script->CurrentlyScripting= FALSE;
670 /* process the ending type action */
671 if (rc == ERROR_SUCCESS)
672 ACTION_PerformActionSequence(package,-1,ui);
673 else if (rc == ERROR_INSTALL_USEREXIT)
674 ACTION_PerformActionSequence(package,-2,ui);
675 else if (rc == ERROR_INSTALL_SUSPEND)
676 ACTION_PerformActionSequence(package,-4,ui);
677 else /* failed */
678 ACTION_PerformActionSequence(package,-3,ui);
680 /* finish up running custom actions */
681 ACTION_FinishCustomActions(package);
683 return rc;
686 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
688 UINT rc = ERROR_SUCCESS;
689 MSIRECORD * row = 0;
690 static const WCHAR ExecSeqQuery[] =
691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
692 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
693 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
694 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
696 static const WCHAR UISeqQuery[] =
697 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
698 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
699 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
700 ' ', '=',' ','%','i',0};
702 if (UI)
703 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
704 else
705 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
707 if (row)
709 LPCWSTR action, cond;
711 TRACE("Running the actions\n");
713 /* check conditions */
714 cond = MSI_RecordGetString(row,2);
715 if (cond)
717 /* this is a hack to skip errors in the condition code */
718 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
719 goto end;
722 action = MSI_RecordGetString(row,1);
723 if (!action)
725 ERR("failed to fetch action\n");
726 rc = ERROR_FUNCTION_FAILED;
727 goto end;
730 if (UI)
731 rc = ACTION_PerformUIAction(package,action);
732 else
733 rc = ACTION_PerformAction(package,action,FALSE);
734 end:
735 msiobj_release(&row->hdr);
737 else
738 rc = ERROR_SUCCESS;
740 return rc;
743 typedef struct {
744 MSIPACKAGE* package;
745 BOOL UI;
746 } iterate_action_param;
748 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
750 iterate_action_param *iap= (iterate_action_param*)param;
751 UINT rc;
752 LPCWSTR cond, action;
754 action = MSI_RecordGetString(row,1);
755 if (!action)
757 ERR("Error is retrieving action name\n");
758 return ERROR_FUNCTION_FAILED;
761 /* check conditions */
762 cond = MSI_RecordGetString(row,2);
763 if (cond)
765 /* this is a hack to skip errors in the condition code */
766 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
768 TRACE("Skipping action: %s (condition is false)\n",
769 debugstr_w(action));
770 return ERROR_SUCCESS;
774 if (iap->UI)
775 rc = ACTION_PerformUIAction(iap->package,action);
776 else
777 rc = ACTION_PerformAction(iap->package,action,FALSE);
779 msi_dialog_check_messages( NULL );
781 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
782 rc = iap->package->CurrentInstallState;
784 if (rc == ERROR_FUNCTION_NOT_CALLED)
785 rc = ERROR_SUCCESS;
787 if (rc != ERROR_SUCCESS)
788 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
790 return rc;
793 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
795 MSIQUERY * view;
796 UINT r;
797 static const WCHAR query[] =
798 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
799 '`','%','s','`',
800 ' ','W','H','E','R','E',' ',
801 '`','S','e','q','u','e','n','c','e','`',' ',
802 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
803 '`','S','e','q','u','e','n','c','e','`',0};
804 iterate_action_param iap;
807 * FIXME: probably should be checking UILevel in the
808 * ACTION_PerformUIAction/ACTION_PerformAction
809 * rather than saving the UI level here. Those
810 * two functions can be merged too.
812 iap.package = package;
813 iap.UI = TRUE;
815 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
817 r = MSI_OpenQuery( package->db, &view, query, szTable );
818 if (r == ERROR_SUCCESS)
820 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
821 msiobj_release(&view->hdr);
824 return r;
827 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
829 MSIQUERY * view;
830 UINT rc;
831 static const WCHAR ExecSeqQuery[] =
832 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
833 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
834 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
835 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
836 'O','R','D','E','R',' ', 'B','Y',' ',
837 '`','S','e','q','u','e','n','c','e','`',0 };
838 MSIRECORD * row = 0;
839 static const WCHAR IVQuery[] =
840 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
841 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
842 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
843 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
844 ' ','\'', 'I','n','s','t','a','l','l',
845 'V','a','l','i','d','a','t','e','\'', 0};
846 INT seq = 0;
847 iterate_action_param iap;
849 iap.package = package;
850 iap.UI = FALSE;
852 if (package->script->ExecuteSequenceRun)
854 TRACE("Execute Sequence already Run\n");
855 return ERROR_SUCCESS;
858 package->script->ExecuteSequenceRun = TRUE;
860 /* get the sequence number */
861 if (UIran)
863 row = MSI_QueryGetRecord(package->db, IVQuery);
864 if( !row )
865 return ERROR_FUNCTION_FAILED;
866 seq = MSI_RecordGetInteger(row,1);
867 msiobj_release(&row->hdr);
870 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
871 if (rc == ERROR_SUCCESS)
873 TRACE("Running the actions\n");
875 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
876 msiobj_release(&view->hdr);
879 return rc;
882 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
884 MSIQUERY * view;
885 UINT rc;
886 static const WCHAR ExecSeqQuery [] =
887 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
888 '`','I','n','s','t','a','l','l',
889 'U','I','S','e','q','u','e','n','c','e','`',
890 ' ','W','H','E','R','E',' ',
891 '`','S','e','q','u','e','n','c','e','`',' ',
892 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
893 '`','S','e','q','u','e','n','c','e','`',0};
894 iterate_action_param iap;
896 iap.package = package;
897 iap.UI = TRUE;
899 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
901 if (rc == ERROR_SUCCESS)
903 TRACE("Running the actions\n");
905 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
906 msiobj_release(&view->hdr);
909 return rc;
912 /********************************************************
913 * ACTION helper functions and functions that perform the actions
914 *******************************************************/
915 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
916 UINT* rc, BOOL force )
918 BOOL ret = FALSE;
919 BOOL run = force;
920 int i;
922 if (!package)
924 ERR("package was null!\n");
925 return FALSE;
928 if (!run && !package->script->CurrentlyScripting)
929 run = TRUE;
931 if (!run)
933 if (strcmpW(action,szInstallFinalize) == 0 ||
934 strcmpW(action,szInstallExecute) == 0 ||
935 strcmpW(action,szInstallExecuteAgain) == 0)
936 run = TRUE;
939 i = 0;
940 while (StandardActions[i].action != NULL)
942 if (strcmpW(StandardActions[i].action, action)==0)
944 if (!run)
946 ui_actioninfo(package, action, TRUE, 0);
947 *rc = schedule_action(package,INSTALL_SCRIPT,action);
948 ui_actioninfo(package, action, FALSE, *rc);
950 else
952 ui_actionstart(package, action);
953 if (StandardActions[i].handler)
955 *rc = StandardActions[i].handler(package);
957 else
959 FIXME("unhandled standard action %s\n",debugstr_w(action));
960 *rc = ERROR_SUCCESS;
963 ret = TRUE;
964 break;
966 i++;
968 return ret;
971 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
972 UINT* rc, BOOL force )
974 BOOL ret=FALSE;
975 UINT arc;
977 arc = ACTION_CustomAction(package,action, force);
979 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
981 *rc = arc;
982 ret = TRUE;
984 return ret;
988 * A lot of actions are really important even if they don't do anything
989 * explicit... Lots of properties are set at the beginning of the installation
990 * CostFinalize does a bunch of work to translate the directories and such
992 * But until I get write access to the database that is hard, so I am going to
993 * hack it to see if I can get something to run.
995 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
997 UINT rc = ERROR_SUCCESS;
998 BOOL handled;
1000 TRACE("Performing action (%s)\n",debugstr_w(action));
1002 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1004 if (!handled)
1005 handled = ACTION_HandleCustomAction(package, action, &rc, force);
1007 if (!handled)
1009 FIXME("unhandled msi action %s\n",debugstr_w(action));
1010 rc = ERROR_FUNCTION_NOT_CALLED;
1013 return rc;
1016 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1018 UINT rc = ERROR_SUCCESS;
1019 BOOL handled = FALSE;
1021 TRACE("Performing action (%s)\n",debugstr_w(action));
1023 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1025 if (!handled)
1026 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1028 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1029 handled = TRUE;
1031 if (!handled)
1033 FIXME("unhandled msi action %s\n",debugstr_w(action));
1034 rc = ERROR_FUNCTION_NOT_CALLED;
1037 return rc;
1042 * Actual Action Handlers
1045 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1047 MSIPACKAGE *package = (MSIPACKAGE*)param;
1048 LPCWSTR dir;
1049 LPWSTR full_path;
1050 MSIRECORD *uirow;
1051 MSIFOLDER *folder;
1053 dir = MSI_RecordGetString(row,1);
1054 if (!dir)
1056 ERR("Unable to get folder id\n");
1057 return ERROR_SUCCESS;
1060 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1061 if (!full_path)
1063 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1064 return ERROR_SUCCESS;
1067 TRACE("Folder is %s\n",debugstr_w(full_path));
1069 /* UI stuff */
1070 uirow = MSI_CreateRecord(1);
1071 MSI_RecordSetStringW(uirow,1,full_path);
1072 ui_actiondata(package,szCreateFolders,uirow);
1073 msiobj_release( &uirow->hdr );
1075 if (folder->State == 0)
1076 create_full_pathW(full_path);
1078 folder->State = 3;
1080 msi_free(full_path);
1081 return ERROR_SUCCESS;
1084 /* FIXME: probably should merge this with the above function */
1085 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1087 UINT rc = ERROR_SUCCESS;
1088 MSIFOLDER *folder;
1089 LPWSTR install_path;
1091 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1092 if (!install_path)
1093 return ERROR_FUNCTION_FAILED;
1095 /* create the path */
1096 if (folder->State == 0)
1098 create_full_pathW(install_path);
1099 folder->State = 2;
1101 msi_free(install_path);
1103 return rc;
1106 UINT msi_create_component_directories( MSIPACKAGE *package )
1108 MSICOMPONENT *comp;
1110 /* create all the folders required by the components are going to install */
1111 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1113 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1114 continue;
1115 msi_create_directory( package, comp->Directory );
1118 return ERROR_SUCCESS;
1122 * Also we cannot enable/disable components either, so for now I am just going
1123 * to do all the directories for all the components.
1125 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1127 static const WCHAR ExecSeqQuery[] =
1128 {'S','E','L','E','C','T',' ',
1129 '`','D','i','r','e','c','t','o','r','y','_','`',
1130 ' ','F','R','O','M',' ',
1131 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1132 UINT rc;
1133 MSIQUERY *view;
1135 /* create all the empty folders specified in the CreateFolder table */
1136 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1137 if (rc != ERROR_SUCCESS)
1138 return ERROR_SUCCESS;
1140 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1141 msiobj_release(&view->hdr);
1143 msi_create_component_directories( package );
1145 return rc;
1148 static MSICOMPONENT* load_component( MSIRECORD * row )
1150 MSICOMPONENT *comp;
1152 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1153 if (!comp)
1154 return comp;
1156 /* fill in the data */
1157 comp->Component = msi_dup_record_field( row, 1 );
1159 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1161 comp->ComponentId = msi_dup_record_field( row, 2 );
1162 comp->Directory = msi_dup_record_field( row, 3 );
1163 comp->Attributes = MSI_RecordGetInteger(row,4);
1164 comp->Condition = msi_dup_record_field( row, 5 );
1165 comp->KeyPath = msi_dup_record_field( row, 6 );
1167 comp->Installed = INSTALLSTATE_ABSENT;
1168 comp->Action = INSTALLSTATE_UNKNOWN;
1169 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1171 comp->Enabled = TRUE;
1173 return comp;
1176 typedef struct {
1177 MSIPACKAGE *package;
1178 MSIFEATURE *feature;
1179 } _ilfs;
1181 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1183 ComponentList *cl;
1185 cl = msi_alloc( sizeof (*cl) );
1186 if ( !cl )
1187 return ERROR_NOT_ENOUGH_MEMORY;
1188 cl->component = comp;
1189 list_add_tail( &feature->Components, &cl->entry );
1191 return ERROR_SUCCESS;
1194 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1196 _ilfs* ilfs= (_ilfs*)param;
1197 MSIPACKAGE *package = ilfs->package;
1198 MSIFEATURE *feature = ilfs->feature;
1199 MSICOMPONENT *comp;
1201 comp = load_component( row );
1202 if (!comp)
1203 return ERROR_FUNCTION_FAILED;
1205 list_add_tail( &package->components, &comp->entry );
1206 add_feature_component( feature, comp );
1208 TRACE("Loaded new component %p\n", comp);
1210 return ERROR_SUCCESS;
1213 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1215 _ilfs* ilfs= (_ilfs*)param;
1216 LPCWSTR component;
1217 DWORD rc;
1218 MSICOMPONENT *comp;
1219 MSIQUERY * view;
1220 static const WCHAR Query[] =
1221 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1222 '`','C','o','m','p','o','n','e','n','t','`',' ',
1223 'W','H','E','R','E',' ',
1224 '`','C','o','m','p','o','n','e','n','t','`',' ',
1225 '=','\'','%','s','\'',0};
1227 component = MSI_RecordGetString(row,1);
1229 /* check to see if the component is already loaded */
1230 comp = get_loaded_component( ilfs->package, component );
1231 if (comp)
1233 TRACE("Component %s already loaded\n", debugstr_w(component) );
1234 add_feature_component( ilfs->feature, comp );
1235 return ERROR_SUCCESS;
1238 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1239 if (rc != ERROR_SUCCESS)
1240 return ERROR_SUCCESS;
1242 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1243 msiobj_release( &view->hdr );
1245 return ERROR_SUCCESS;
1248 static UINT load_feature(MSIRECORD * row, LPVOID param)
1250 MSIPACKAGE* package = (MSIPACKAGE*)param;
1251 MSIFEATURE* feature;
1252 static const WCHAR Query1[] =
1253 {'S','E','L','E','C','T',' ',
1254 '`','C','o','m','p','o','n','e','n','t','_','`',
1255 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1256 'C','o','m','p','o','n','e','n','t','s','`',' ',
1257 'W','H','E','R','E',' ',
1258 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1259 MSIQUERY * view;
1260 UINT rc;
1261 _ilfs ilfs;
1263 /* fill in the data */
1265 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1266 if (!feature)
1267 return ERROR_NOT_ENOUGH_MEMORY;
1269 list_init( &feature->Components );
1271 feature->Feature = msi_dup_record_field( row, 1 );
1273 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1275 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1276 feature->Title = msi_dup_record_field( row, 3 );
1277 feature->Description = msi_dup_record_field( row, 4 );
1279 if (!MSI_RecordIsNull(row,5))
1280 feature->Display = MSI_RecordGetInteger(row,5);
1282 feature->Level= MSI_RecordGetInteger(row,6);
1283 feature->Directory = msi_dup_record_field( row, 7 );
1284 feature->Attributes = MSI_RecordGetInteger(row,8);
1286 feature->Installed = INSTALLSTATE_ABSENT;
1287 feature->Action = INSTALLSTATE_UNKNOWN;
1288 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1290 list_add_tail( &package->features, &feature->entry );
1292 /* load feature components */
1294 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1295 if (rc != ERROR_SUCCESS)
1296 return ERROR_SUCCESS;
1298 ilfs.package = package;
1299 ilfs.feature = feature;
1301 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1302 msiobj_release(&view->hdr);
1304 return ERROR_SUCCESS;
1307 static UINT load_file(MSIRECORD *row, LPVOID param)
1309 MSIPACKAGE* package = (MSIPACKAGE*)param;
1310 LPCWSTR component;
1311 MSIFILE *file;
1313 /* fill in the data */
1315 file = msi_alloc_zero( sizeof (MSIFILE) );
1316 if (!file)
1317 return ERROR_NOT_ENOUGH_MEMORY;
1319 file->File = msi_dup_record_field( row, 1 );
1321 component = MSI_RecordGetString( row, 2 );
1322 file->Component = get_loaded_component( package, component );
1324 if (!file->Component)
1325 ERR("Unfound Component %s\n",debugstr_w(component));
1327 file->FileName = msi_dup_record_field( row, 3 );
1328 reduce_to_longfilename( file->FileName );
1330 file->ShortName = msi_dup_record_field( row, 3 );
1331 reduce_to_shortfilename( file->ShortName );
1333 file->FileSize = MSI_RecordGetInteger( row, 4 );
1334 file->Version = msi_dup_record_field( row, 5 );
1335 file->Language = msi_dup_record_field( row, 6 );
1336 file->Attributes = MSI_RecordGetInteger( row, 7 );
1337 file->Sequence = MSI_RecordGetInteger( row, 8 );
1339 file->state = msifs_invalid;
1341 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1343 list_add_tail( &package->files, &file->entry );
1345 return ERROR_SUCCESS;
1348 static UINT load_all_files(MSIPACKAGE *package)
1350 MSIQUERY * view;
1351 UINT rc;
1352 static const WCHAR Query[] =
1353 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1354 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1355 '`','S','e','q','u','e','n','c','e','`', 0};
1357 if (!package)
1358 return ERROR_INVALID_HANDLE;
1360 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1361 if (rc != ERROR_SUCCESS)
1362 return ERROR_SUCCESS;
1364 rc = MSI_IterateRecords(view, NULL, load_file, package);
1365 msiobj_release(&view->hdr);
1367 return ERROR_SUCCESS;
1372 * I am not doing any of the costing functionality yet.
1373 * Mostly looking at doing the Component and Feature loading
1375 * The native MSI does A LOT of modification to tables here. Mostly adding
1376 * a lot of temporary columns to the Feature and Component tables.
1378 * note: Native msi also tracks the short filename. But I am only going to
1379 * track the long ones. Also looking at this directory table
1380 * it appears that the directory table does not get the parents
1381 * resolved base on property only based on their entries in the
1382 * directory table.
1384 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1386 MSIQUERY * view;
1387 UINT rc;
1388 static const WCHAR Query_all[] =
1389 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1390 '`','F','e','a','t','u','r','e','`',0};
1391 static const WCHAR szCosting[] =
1392 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1393 static const WCHAR szZero[] = { '0', 0 };
1395 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1396 return ERROR_SUCCESS;
1398 MSI_SetPropertyW(package, szCosting, szZero);
1399 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1401 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1402 if (rc != ERROR_SUCCESS)
1403 return rc;
1405 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1406 msiobj_release(&view->hdr);
1408 load_all_files(package);
1410 return ERROR_SUCCESS;
1413 static UINT execute_script(MSIPACKAGE *package, UINT script )
1415 int i;
1416 UINT rc = ERROR_SUCCESS;
1418 TRACE("Executing Script %i\n",script);
1420 if (!package->script)
1422 ERR("no script!\n");
1423 return ERROR_FUNCTION_FAILED;
1426 for (i = 0; i < package->script->ActionCount[script]; i++)
1428 LPWSTR action;
1429 action = package->script->Actions[script][i];
1430 ui_actionstart(package, action);
1431 TRACE("Executing Action (%s)\n",debugstr_w(action));
1432 rc = ACTION_PerformAction(package, action, TRUE);
1433 msi_free(package->script->Actions[script][i]);
1434 if (rc != ERROR_SUCCESS)
1435 break;
1437 msi_free(package->script->Actions[script]);
1439 package->script->ActionCount[script] = 0;
1440 package->script->Actions[script] = NULL;
1441 return rc;
1444 static UINT ACTION_FileCost(MSIPACKAGE *package)
1446 return ERROR_SUCCESS;
1450 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1452 static const WCHAR Query[] =
1453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1454 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1455 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1456 ' ','=',' ','\'','%','s','\'',
1458 LPWSTR ptargetdir, targetdir, srcdir;
1459 LPCWSTR parent;
1460 LPWSTR shortname = NULL;
1461 MSIRECORD * row = 0;
1462 MSIFOLDER *folder;
1464 TRACE("Looking for dir %s\n",debugstr_w(dir));
1466 folder = get_loaded_folder( package, dir );
1467 if (folder)
1468 return folder;
1470 TRACE("Working to load %s\n",debugstr_w(dir));
1472 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1473 if (!folder)
1474 return NULL;
1476 folder->Directory = strdupW(dir);
1478 row = MSI_QueryGetRecord(package->db, Query, dir);
1479 if (!row)
1480 return NULL;
1482 ptargetdir = targetdir = msi_dup_record_field(row,3);
1484 /* split src and target dir */
1485 if (strchrW(targetdir,':'))
1487 srcdir=strchrW(targetdir,':');
1488 *srcdir=0;
1489 srcdir ++;
1491 else
1492 srcdir=NULL;
1494 /* for now only pick long filename versions */
1495 if (strchrW(targetdir,'|'))
1497 shortname = targetdir;
1498 targetdir = strchrW(targetdir,'|');
1499 *targetdir = 0;
1500 targetdir ++;
1502 /* for the sourcedir pick the short filename */
1503 if (srcdir && strchrW(srcdir,'|'))
1505 LPWSTR p = strchrW(srcdir,'|');
1506 *p = 0;
1509 /* now check for root dirs */
1510 if (targetdir[0] == '.' && targetdir[1] == 0)
1511 targetdir = NULL;
1513 if (targetdir)
1515 TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));
1516 msi_free( folder->TargetDefault);
1517 folder->TargetDefault = strdupW(targetdir);
1520 if (srcdir)
1521 folder->SourceDefault = strdupW(srcdir);
1522 else if (shortname)
1523 folder->SourceDefault = strdupW(shortname);
1524 else if (targetdir)
1525 folder->SourceDefault = strdupW(targetdir);
1526 msi_free(ptargetdir);
1527 TRACE(" SourceDefault = %s\n", debugstr_w( folder->SourceDefault ));
1529 parent = MSI_RecordGetString(row,2);
1530 if (parent)
1532 folder->Parent = load_folder( package, parent );
1533 if ( folder->Parent )
1534 TRACE("loaded parent %p %s\n", folder->Parent,
1535 debugstr_w(folder->Parent->Directory));
1536 else
1537 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1540 folder->Property = msi_dup_property( package, dir );
1542 msiobj_release(&row->hdr);
1544 list_add_tail( &package->folders, &folder->entry );
1546 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1548 return folder;
1551 /* scan for and update current install states */
1552 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1554 MSICOMPONENT *comp;
1555 MSIFEATURE *feature;
1557 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1559 INSTALLSTATE res;
1560 res = MsiGetComponentPathW( package->ProductCode,
1561 comp->ComponentId, NULL, NULL);
1562 if (res < 0)
1563 res = INSTALLSTATE_ABSENT;
1564 comp->Installed = res;
1567 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1569 ComponentList *cl;
1570 INSTALLSTATE res = -10;
1572 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1574 comp= cl->component;
1576 if (res == -10)
1577 res = comp->Installed;
1578 else
1580 if (res == comp->Installed)
1581 continue;
1583 if (res != comp->Installed)
1584 res = INSTALLSTATE_INCOMPLETE;
1587 feature->Installed = res;
1591 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1592 INSTALLSTATE state)
1594 static const WCHAR all[]={'A','L','L',0};
1595 LPWSTR override;
1596 MSIFEATURE *feature;
1598 override = msi_dup_property( package, property );
1599 if (!override)
1600 return FALSE;
1602 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1604 if (strcmpiW(override,all)==0)
1606 feature->ActionRequest= state;
1607 feature->Action = state;
1609 else
1611 LPWSTR ptr = override;
1612 LPWSTR ptr2 = strchrW(override,',');
1614 while (ptr)
1616 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1617 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1619 feature->ActionRequest= state;
1620 feature->Action = state;
1621 break;
1623 if (ptr2)
1625 ptr=ptr2+1;
1626 ptr2 = strchrW(ptr,',');
1628 else
1629 break;
1633 msi_free(override);
1635 return TRUE;
1638 static UINT SetFeatureStates(MSIPACKAGE *package)
1640 int install_level;
1641 static const WCHAR szlevel[] =
1642 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1643 static const WCHAR szAddLocal[] =
1644 {'A','D','D','L','O','C','A','L',0};
1645 static const WCHAR szRemove[] =
1646 {'R','E','M','O','V','E',0};
1647 static const WCHAR szReinstall[] =
1648 {'R','E','I','N','S','T','A','L','L',0};
1649 BOOL override = FALSE;
1650 MSICOMPONENT* component;
1651 MSIFEATURE *feature;
1654 /* I do not know if this is where it should happen.. but */
1656 TRACE("Checking Install Level\n");
1658 install_level = msi_get_property_int( package, szlevel, 1 );
1660 /* ok hereis the _real_ rub
1661 * all these activation/deactivation things happen in order and things
1662 * later on the list override things earlier on the list.
1663 * 1) INSTALLLEVEL processing
1664 * 2) ADDLOCAL
1665 * 3) REMOVE
1666 * 4) ADDSOURCE
1667 * 5) ADDDEFAULT
1668 * 6) REINSTALL
1669 * 7) COMPADDLOCAL
1670 * 8) COMPADDSOURCE
1671 * 9) FILEADDLOCAL
1672 * 10) FILEADDSOURCE
1673 * 11) FILEADDDEFAULT
1674 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1675 * ignored for all the features. seems strange, especially since it is not
1676 * documented anywhere, but it is how it works.
1678 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1679 * REMOVE are the big ones, since we don't handle administrative installs
1680 * yet anyway.
1682 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1683 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1684 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1686 if (!override)
1688 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1690 BOOL feature_state = ((feature->Level > 0) &&
1691 (feature->Level <= install_level));
1693 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1695 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1697 feature->ActionRequest = INSTALLSTATE_SOURCE;
1698 feature->Action = INSTALLSTATE_SOURCE;
1700 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1702 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1703 feature->Action = INSTALLSTATE_ADVERTISED;
1705 else
1707 feature->ActionRequest = INSTALLSTATE_LOCAL;
1708 feature->Action = INSTALLSTATE_LOCAL;
1713 else
1715 /* set the Preselected Property */
1716 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1717 static const WCHAR szOne[] = { '1', 0 };
1719 MSI_SetPropertyW(package,szPreselected,szOne);
1723 * now we want to enable or disable components base on feature
1726 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1728 ComponentList *cl;
1730 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1731 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1732 feature->ActionRequest);
1734 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1736 component = cl->component;
1738 if (!component->Enabled)
1740 component->Action = INSTALLSTATE_UNKNOWN;
1741 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1743 else
1745 if (feature->Action == INSTALLSTATE_LOCAL)
1747 component->Action = INSTALLSTATE_LOCAL;
1748 component->ActionRequest = INSTALLSTATE_LOCAL;
1750 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1752 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1753 (component->Action == INSTALLSTATE_ABSENT) ||
1754 (component->Action == INSTALLSTATE_ADVERTISED))
1757 component->Action = INSTALLSTATE_SOURCE;
1758 component->ActionRequest = INSTALLSTATE_SOURCE;
1761 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1763 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1764 (component->Action == INSTALLSTATE_ABSENT))
1767 component->Action = INSTALLSTATE_ADVERTISED;
1768 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1771 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1773 if (component->Action == INSTALLSTATE_UNKNOWN)
1775 component->Action = INSTALLSTATE_ABSENT;
1776 component->ActionRequest = INSTALLSTATE_ABSENT;
1783 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1785 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1786 debugstr_w(component->Component), component->Installed,
1787 component->Action, component->ActionRequest);
1791 return ERROR_SUCCESS;
1794 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1796 MSIPACKAGE *package = (MSIPACKAGE*)param;
1797 LPCWSTR name;
1798 LPWSTR path;
1800 name = MSI_RecordGetString(row,1);
1802 /* This helper function now does ALL the work */
1803 TRACE("Dir %s ...\n",debugstr_w(name));
1804 load_folder(package,name);
1805 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1806 TRACE("resolves to %s\n",debugstr_w(path));
1807 msi_free(path);
1809 return ERROR_SUCCESS;
1812 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1814 MSIPACKAGE *package = (MSIPACKAGE*)param;
1815 LPCWSTR name;
1816 MSIFEATURE *feature;
1818 name = MSI_RecordGetString( row, 1 );
1820 feature = get_loaded_feature( package, name );
1821 if (!feature)
1822 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1823 else
1825 LPCWSTR Condition;
1826 Condition = MSI_RecordGetString(row,3);
1828 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1830 int level = MSI_RecordGetInteger(row,2);
1831 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1832 feature->Level = level;
1835 return ERROR_SUCCESS;
1840 * A lot is done in this function aside from just the costing.
1841 * The costing needs to be implemented at some point but for now I am going
1842 * to focus on the directory building
1845 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1847 static const WCHAR ExecSeqQuery[] =
1848 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1849 '`','D','i','r','e','c','t','o','r','y','`',0};
1850 static const WCHAR ConditionQuery[] =
1851 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1852 '`','C','o','n','d','i','t','i','o','n','`',0};
1853 static const WCHAR szCosting[] =
1854 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1855 static const WCHAR szlevel[] =
1856 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1857 static const WCHAR szOne[] = { '1', 0 };
1858 MSICOMPONENT *comp;
1859 MSIFILE *file;
1860 UINT rc;
1861 MSIQUERY * view;
1862 LPWSTR level;
1864 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1865 return ERROR_SUCCESS;
1867 TRACE("Building Directory properties\n");
1869 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1870 if (rc == ERROR_SUCCESS)
1872 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1873 package);
1874 msiobj_release(&view->hdr);
1877 TRACE("File calculations\n");
1879 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1881 MSICOMPONENT* comp = file->Component;
1882 LPWSTR p;
1884 if (!comp)
1885 continue;
1887 /* calculate target */
1888 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1890 msi_free(file->TargetPath);
1892 TRACE("file %s is named %s\n",
1893 debugstr_w(file->File),debugstr_w(file->FileName));
1895 file->TargetPath = build_directory_name(2, p, file->FileName);
1897 msi_free(p);
1899 TRACE("file %s resolves to %s\n",
1900 debugstr_w(file->File),debugstr_w(file->TargetPath));
1902 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1904 file->state = msifs_missing;
1905 comp->Cost += file->FileSize;
1906 continue;
1909 if (file->Version)
1911 DWORD handle;
1912 DWORD versize;
1913 UINT sz;
1914 LPVOID version;
1915 static WCHAR name[] = {'\\',0};
1916 static const WCHAR name_fmt[] =
1917 {'%','u','.','%','u','.','%','u','.','%','u',0};
1918 WCHAR filever[0x100];
1919 VS_FIXEDFILEINFO *lpVer;
1921 TRACE("Version comparison..\n");
1922 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1923 version = msi_alloc(versize);
1924 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1926 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1928 sprintfW(filever,name_fmt,
1929 HIWORD(lpVer->dwFileVersionMS),
1930 LOWORD(lpVer->dwFileVersionMS),
1931 HIWORD(lpVer->dwFileVersionLS),
1932 LOWORD(lpVer->dwFileVersionLS));
1934 TRACE("new %s old %s\n", debugstr_w(file->Version),
1935 debugstr_w(filever));
1936 if (strcmpiW(filever,file->Version)<0)
1938 file->state = msifs_overwrite;
1939 /* FIXME: cost should be diff in size */
1940 comp->Cost += file->FileSize;
1942 else
1943 file->state = msifs_present;
1944 msi_free(version);
1946 else
1947 file->state = msifs_present;
1950 TRACE("Evaluating Condition Table\n");
1952 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1953 if (rc == ERROR_SUCCESS)
1955 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1956 package);
1957 msiobj_release(&view->hdr);
1960 TRACE("Enabling or Disabling Components\n");
1961 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1963 if (comp->Condition)
1965 if (MSI_EvaluateConditionW(package,
1966 comp->Condition) == MSICONDITION_FALSE)
1968 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1969 comp->Enabled = FALSE;
1974 MSI_SetPropertyW(package,szCosting,szOne);
1975 /* set default run level if not set */
1976 level = msi_dup_property( package, szlevel );
1977 if (!level)
1978 MSI_SetPropertyW(package,szlevel, szOne);
1979 msi_free(level);
1981 ACTION_UpdateInstallStates(package);
1983 return SetFeatureStates(package);
1986 /* OK this value is "interpreted" and then formatted based on the
1987 first few characters */
1988 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1989 DWORD *size)
1991 LPSTR data = NULL;
1992 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1994 if (value[1]=='x')
1996 LPWSTR ptr;
1997 CHAR byte[5];
1998 LPWSTR deformated = NULL;
1999 int count;
2001 deformat_string(package, &value[2], &deformated);
2003 /* binary value type */
2004 ptr = deformated;
2005 *type = REG_BINARY;
2006 if (strlenW(ptr)%2)
2007 *size = (strlenW(ptr)/2)+1;
2008 else
2009 *size = strlenW(ptr)/2;
2011 data = msi_alloc(*size);
2013 byte[0] = '0';
2014 byte[1] = 'x';
2015 byte[4] = 0;
2016 count = 0;
2017 /* if uneven pad with a zero in front */
2018 if (strlenW(ptr)%2)
2020 byte[2]= '0';
2021 byte[3]= *ptr;
2022 ptr++;
2023 data[count] = (BYTE)strtol(byte,NULL,0);
2024 count ++;
2025 TRACE("Uneven byte count\n");
2027 while (*ptr)
2029 byte[2]= *ptr;
2030 ptr++;
2031 byte[3]= *ptr;
2032 ptr++;
2033 data[count] = (BYTE)strtol(byte,NULL,0);
2034 count ++;
2036 msi_free(deformated);
2038 TRACE("Data %li bytes(%i)\n",*size,count);
2040 else
2042 LPWSTR deformated;
2043 LPWSTR p;
2044 DWORD d = 0;
2045 deformat_string(package, &value[1], &deformated);
2047 *type=REG_DWORD;
2048 *size = sizeof(DWORD);
2049 data = msi_alloc(*size);
2050 p = deformated;
2051 if (*p == '-')
2052 p++;
2053 while (*p)
2055 if ( (*p < '0') || (*p > '9') )
2056 break;
2057 d *= 10;
2058 d += (*p - '0');
2059 p++;
2061 if (deformated[0] == '-')
2062 d = -d;
2063 *(LPDWORD)data = d;
2064 TRACE("DWORD %li\n",*(LPDWORD)data);
2066 msi_free(deformated);
2069 else
2071 static const WCHAR szMulti[] = {'[','~',']',0};
2072 LPCWSTR ptr;
2073 *type=REG_SZ;
2075 if (value[0]=='#')
2077 if (value[1]=='%')
2079 ptr = &value[2];
2080 *type=REG_EXPAND_SZ;
2082 else
2083 ptr = &value[1];
2085 else
2086 ptr=value;
2088 if (strstrW(value,szMulti))
2089 *type = REG_MULTI_SZ;
2091 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2093 return data;
2096 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2098 MSIPACKAGE *package = (MSIPACKAGE*)param;
2099 static const WCHAR szHCR[] =
2100 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2101 'R','O','O','T','\\',0};
2102 static const WCHAR szHCU[] =
2103 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2104 'U','S','E','R','\\',0};
2105 static const WCHAR szHLM[] =
2106 {'H','K','E','Y','_','L','O','C','A','L','_',
2107 'M','A','C','H','I','N','E','\\',0};
2108 static const WCHAR szHU[] =
2109 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2111 LPSTR value_data = NULL;
2112 HKEY root_key, hkey;
2113 DWORD type,size;
2114 LPWSTR deformated;
2115 LPCWSTR szRoot, component, name, key, value;
2116 MSICOMPONENT *comp;
2117 MSIRECORD * uirow;
2118 LPWSTR uikey;
2119 INT root;
2120 BOOL check_first = FALSE;
2121 UINT rc;
2123 ui_progress(package,2,0,0,0);
2125 value = NULL;
2126 key = NULL;
2127 uikey = NULL;
2128 name = NULL;
2130 component = MSI_RecordGetString(row, 6);
2131 comp = get_loaded_component(package,component);
2132 if (!comp)
2133 return ERROR_SUCCESS;
2135 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2137 TRACE("Skipping write due to disabled component %s\n",
2138 debugstr_w(component));
2140 comp->Action = comp->Installed;
2142 return ERROR_SUCCESS;
2145 comp->Action = INSTALLSTATE_LOCAL;
2147 name = MSI_RecordGetString(row, 4);
2148 if( MSI_RecordIsNull(row,5) && name )
2150 /* null values can have special meanings */
2151 if (name[0]=='-' && name[1] == 0)
2152 return ERROR_SUCCESS;
2153 else if ((name[0]=='+' && name[1] == 0) ||
2154 (name[0] == '*' && name[1] == 0))
2155 name = NULL;
2156 check_first = TRUE;
2159 root = MSI_RecordGetInteger(row,2);
2160 key = MSI_RecordGetString(row, 3);
2162 /* get the root key */
2163 switch (root)
2165 case -1:
2167 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2168 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2169 if (all_users && all_users[0] == '1')
2171 root_key = HKEY_LOCAL_MACHINE;
2172 szRoot = szHLM;
2174 else
2176 root_key = HKEY_CURRENT_USER;
2177 szRoot = szHCU;
2179 msi_free(all_users);
2181 break;
2182 case 0: root_key = HKEY_CLASSES_ROOT;
2183 szRoot = szHCR;
2184 break;
2185 case 1: root_key = HKEY_CURRENT_USER;
2186 szRoot = szHCU;
2187 break;
2188 case 2: root_key = HKEY_LOCAL_MACHINE;
2189 szRoot = szHLM;
2190 break;
2191 case 3: root_key = HKEY_USERS;
2192 szRoot = szHU;
2193 break;
2194 default:
2195 ERR("Unknown root %i\n",root);
2196 root_key=NULL;
2197 szRoot = NULL;
2198 break;
2200 if (!root_key)
2201 return ERROR_SUCCESS;
2203 deformat_string(package, key , &deformated);
2204 size = strlenW(deformated) + strlenW(szRoot) + 1;
2205 uikey = msi_alloc(size*sizeof(WCHAR));
2206 strcpyW(uikey,szRoot);
2207 strcatW(uikey,deformated);
2209 if (RegCreateKeyW( root_key, deformated, &hkey))
2211 ERR("Could not create key %s\n",debugstr_w(deformated));
2212 msi_free(deformated);
2213 msi_free(uikey);
2214 return ERROR_SUCCESS;
2216 msi_free(deformated);
2218 value = MSI_RecordGetString(row,5);
2219 if (value)
2220 value_data = parse_value(package, value, &type, &size);
2221 else
2223 static const WCHAR szEmpty[] = {0};
2224 value_data = (LPSTR)strdupW(szEmpty);
2225 size = 0;
2226 type = REG_SZ;
2229 deformat_string(package, name, &deformated);
2231 /* get the double nulls to terminate SZ_MULTI */
2232 if (type == REG_MULTI_SZ)
2233 size +=sizeof(WCHAR);
2235 if (!check_first)
2237 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2238 debugstr_w(uikey));
2239 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2241 else
2243 DWORD sz = 0;
2244 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2245 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2247 TRACE("value %s of %s checked already exists\n",
2248 debugstr_w(deformated), debugstr_w(uikey));
2250 else
2252 TRACE("Checked and setting value %s of %s\n",
2253 debugstr_w(deformated), debugstr_w(uikey));
2254 if (deformated || size)
2255 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2258 RegCloseKey(hkey);
2260 uirow = MSI_CreateRecord(3);
2261 MSI_RecordSetStringW(uirow,2,deformated);
2262 MSI_RecordSetStringW(uirow,1,uikey);
2264 if (type == REG_SZ)
2265 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2266 else
2267 MSI_RecordSetStringW(uirow,3,value);
2269 ui_actiondata(package,szWriteRegistryValues,uirow);
2270 msiobj_release( &uirow->hdr );
2272 msi_free(value_data);
2273 msi_free(deformated);
2274 msi_free(uikey);
2276 return ERROR_SUCCESS;
2279 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2281 UINT rc;
2282 MSIQUERY * view;
2283 static const WCHAR ExecSeqQuery[] =
2284 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2285 '`','R','e','g','i','s','t','r','y','`',0 };
2287 if (!package)
2288 return ERROR_INVALID_HANDLE;
2290 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2291 if (rc != ERROR_SUCCESS)
2292 return ERROR_SUCCESS;
2294 /* increment progress bar each time action data is sent */
2295 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2297 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2299 msiobj_release(&view->hdr);
2300 return rc;
2303 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2305 package->script->CurrentlyScripting = TRUE;
2307 return ERROR_SUCCESS;
2311 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2313 MSICOMPONENT *comp;
2314 DWORD progress = 0;
2315 DWORD total = 0;
2316 static const WCHAR q1[]=
2317 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2318 '`','R','e','g','i','s','t','r','y','`',0};
2319 UINT rc;
2320 MSIQUERY * view;
2321 MSIFEATURE *feature;
2322 MSIFILE *file;
2324 TRACE("InstallValidate\n");
2326 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2327 if (rc == ERROR_SUCCESS)
2329 MSI_IterateRecords( view, &progress, NULL, package );
2330 msiobj_release( &view->hdr );
2331 total += progress * REG_PROGRESS_VALUE;
2334 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2335 total += COMPONENT_PROGRESS_VALUE;
2337 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2338 total += file->FileSize;
2340 ui_progress(package,0,total,0,0);
2342 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2344 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2345 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2346 feature->ActionRequest);
2349 return ERROR_SUCCESS;
2352 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2354 MSIPACKAGE* package = (MSIPACKAGE*)param;
2355 LPCWSTR cond = NULL;
2356 LPCWSTR message = NULL;
2357 static const WCHAR title[]=
2358 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2360 cond = MSI_RecordGetString(row,1);
2362 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2364 LPWSTR deformated;
2365 message = MSI_RecordGetString(row,2);
2366 deformat_string(package,message,&deformated);
2367 MessageBoxW(NULL,deformated,title,MB_OK);
2368 msi_free(deformated);
2369 return ERROR_FUNCTION_FAILED;
2372 return ERROR_SUCCESS;
2375 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2377 UINT rc;
2378 MSIQUERY * view = NULL;
2379 static const WCHAR ExecSeqQuery[] =
2380 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2381 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2383 TRACE("Checking launch conditions\n");
2385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2386 if (rc != ERROR_SUCCESS)
2387 return ERROR_SUCCESS;
2389 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2390 msiobj_release(&view->hdr);
2392 return rc;
2395 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2398 if (!cmp->KeyPath)
2399 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2401 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2403 MSIRECORD * row = 0;
2404 UINT root,len;
2405 LPWSTR deformated,buffer,deformated_name;
2406 LPCWSTR key,name;
2407 static const WCHAR ExecSeqQuery[] =
2408 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2409 '`','R','e','g','i','s','t','r','y','`',' ',
2410 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2411 ' ','=',' ' ,'\'','%','s','\'',0 };
2412 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2413 static const WCHAR fmt2[]=
2414 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2416 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2417 if (!row)
2418 return NULL;
2420 root = MSI_RecordGetInteger(row,2);
2421 key = MSI_RecordGetString(row, 3);
2422 name = MSI_RecordGetString(row, 4);
2423 deformat_string(package, key , &deformated);
2424 deformat_string(package, name, &deformated_name);
2426 len = strlenW(deformated) + 6;
2427 if (deformated_name)
2428 len+=strlenW(deformated_name);
2430 buffer = msi_alloc( len *sizeof(WCHAR));
2432 if (deformated_name)
2433 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2434 else
2435 sprintfW(buffer,fmt,root,deformated);
2437 msi_free(deformated);
2438 msi_free(deformated_name);
2439 msiobj_release(&row->hdr);
2441 return buffer;
2443 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2445 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2446 return NULL;
2448 else
2450 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2452 if (file)
2453 return strdupW( file->TargetPath );
2455 return NULL;
2458 static HKEY openSharedDLLsKey(void)
2460 HKEY hkey=0;
2461 static const WCHAR path[] =
2462 {'S','o','f','t','w','a','r','e','\\',
2463 'M','i','c','r','o','s','o','f','t','\\',
2464 'W','i','n','d','o','w','s','\\',
2465 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2466 'S','h','a','r','e','d','D','L','L','s',0};
2468 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2469 return hkey;
2472 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2474 HKEY hkey;
2475 DWORD count=0;
2476 DWORD type;
2477 DWORD sz = sizeof(count);
2478 DWORD rc;
2480 hkey = openSharedDLLsKey();
2481 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2482 if (rc != ERROR_SUCCESS)
2483 count = 0;
2484 RegCloseKey(hkey);
2485 return count;
2488 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2490 HKEY hkey;
2492 hkey = openSharedDLLsKey();
2493 if (count > 0)
2494 msi_reg_set_val_dword( hkey, path, count );
2495 else
2496 RegDeleteValueW(hkey,path);
2497 RegCloseKey(hkey);
2498 return count;
2502 * Return TRUE if the count should be written out and FALSE if not
2504 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2506 MSIFEATURE *feature;
2507 INT count = 0;
2508 BOOL write = FALSE;
2510 /* only refcount DLLs */
2511 if (comp->KeyPath == NULL ||
2512 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2513 comp->Attributes & msidbComponentAttributesODBCDataSource)
2514 write = FALSE;
2515 else
2517 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2518 write = (count > 0);
2520 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2521 write = TRUE;
2524 /* increment counts */
2525 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2527 ComponentList *cl;
2529 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2530 continue;
2532 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2534 if ( cl->component == comp )
2535 count++;
2539 /* decrement counts */
2540 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2542 ComponentList *cl;
2544 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2545 continue;
2547 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2549 if ( cl->component == comp )
2550 count--;
2554 /* ref count all the files in the component */
2555 if (write)
2557 MSIFILE *file;
2559 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2561 if (file->Component == comp)
2562 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2566 /* add a count for permenent */
2567 if (comp->Attributes & msidbComponentAttributesPermanent)
2568 count ++;
2570 comp->RefCount = count;
2572 if (write)
2573 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2577 * Ok further analysis makes me think that this work is
2578 * actually done in the PublishComponents and PublishFeatures
2579 * step, and not here. It appears like the keypath and all that is
2580 * resolved in this step, however actually written in the Publish steps.
2581 * But we will leave it here for now because it is unclear
2583 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2585 WCHAR squished_pc[GUID_SIZE];
2586 WCHAR squished_cc[GUID_SIZE];
2587 UINT rc;
2588 MSICOMPONENT *comp;
2589 HKEY hkey=0,hkey2=0;
2591 /* writes the Component and Features values to the registry */
2593 rc = MSIREG_OpenComponents(&hkey);
2594 if (rc != ERROR_SUCCESS)
2595 goto end;
2597 squash_guid(package->ProductCode,squished_pc);
2598 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2600 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2602 ui_progress(package,2,0,0,0);
2603 if (comp->ComponentId)
2605 MSIRECORD * uirow;
2607 squash_guid(comp->ComponentId,squished_cc);
2609 msi_free(comp->FullKeypath);
2610 comp->FullKeypath = resolve_keypath( package, comp );
2612 /* do the refcounting */
2613 ACTION_RefCountComponent( package, comp );
2615 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2616 debugstr_w(comp->Component),
2617 debugstr_w(squished_cc),
2618 debugstr_w(comp->FullKeypath),
2619 comp->RefCount);
2621 * Write the keypath out if the component is to be registered
2622 * and delete the key if the component is to be deregistered
2624 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2626 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2627 if (rc != ERROR_SUCCESS)
2628 continue;
2630 if (comp->FullKeypath)
2632 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2634 if (comp->Attributes & msidbComponentAttributesPermanent)
2636 static const WCHAR szPermKey[] =
2637 { '0','0','0','0','0','0','0','0','0','0','0','0',
2638 '0','0','0','0','0','0','0','0','0','0','0','0',
2639 '0','0','0','0','0','0','0','0',0};
2641 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2644 RegCloseKey(hkey2);
2646 /* UI stuff */
2647 uirow = MSI_CreateRecord(3);
2648 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2649 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2650 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2651 ui_actiondata(package,szProcessComponents,uirow);
2652 msiobj_release( &uirow->hdr );
2655 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2657 DWORD res;
2659 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2660 if (rc != ERROR_SUCCESS)
2661 continue;
2663 RegDeleteValueW(hkey2,squished_pc);
2665 /* if the key is empty delete it */
2666 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2667 RegCloseKey(hkey2);
2668 if (res == ERROR_NO_MORE_ITEMS)
2669 RegDeleteKeyW(hkey,squished_cc);
2671 /* UI stuff */
2672 uirow = MSI_CreateRecord(2);
2673 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2674 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2675 ui_actiondata(package,szProcessComponents,uirow);
2676 msiobj_release( &uirow->hdr );
2680 end:
2681 RegCloseKey(hkey);
2682 return rc;
2685 typedef struct {
2686 CLSID clsid;
2687 LPWSTR source;
2689 LPWSTR path;
2690 ITypeLib *ptLib;
2691 } typelib_struct;
2693 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2694 LPWSTR lpszName, LONG_PTR lParam)
2696 TLIBATTR *attr;
2697 typelib_struct *tl_struct = (typelib_struct*) lParam;
2698 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2699 int sz;
2700 HRESULT res;
2702 if (!IS_INTRESOURCE(lpszName))
2704 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2705 return TRUE;
2708 sz = strlenW(tl_struct->source)+4;
2709 sz *= sizeof(WCHAR);
2711 if ((INT)lpszName == 1)
2712 tl_struct->path = strdupW(tl_struct->source);
2713 else
2715 tl_struct->path = msi_alloc(sz);
2716 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2719 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2720 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2721 if (!SUCCEEDED(res))
2723 msi_free(tl_struct->path);
2724 tl_struct->path = NULL;
2726 return TRUE;
2729 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2730 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2732 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2733 return FALSE;
2736 msi_free(tl_struct->path);
2737 tl_struct->path = NULL;
2739 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2740 ITypeLib_Release(tl_struct->ptLib);
2742 return TRUE;
2745 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2747 MSIPACKAGE* package = (MSIPACKAGE*)param;
2748 LPCWSTR component;
2749 MSICOMPONENT *comp;
2750 MSIFILE *file;
2751 typelib_struct tl_struct;
2752 HMODULE module;
2753 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2755 component = MSI_RecordGetString(row,3);
2756 comp = get_loaded_component(package,component);
2757 if (!comp)
2758 return ERROR_SUCCESS;
2760 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2762 TRACE("Skipping typelib reg due to disabled component\n");
2764 comp->Action = comp->Installed;
2766 return ERROR_SUCCESS;
2769 comp->Action = INSTALLSTATE_LOCAL;
2771 file = get_loaded_file( package, comp->KeyPath );
2772 if (!file)
2773 return ERROR_SUCCESS;
2775 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2776 if (module)
2778 LPCWSTR guid;
2779 guid = MSI_RecordGetString(row,1);
2780 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2781 tl_struct.source = strdupW( file->TargetPath );
2782 tl_struct.path = NULL;
2784 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2785 (LONG_PTR)&tl_struct);
2787 if (tl_struct.path)
2789 LPWSTR help = NULL;
2790 LPCWSTR helpid;
2791 HRESULT res;
2793 helpid = MSI_RecordGetString(row,6);
2795 if (helpid)
2796 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2797 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2798 msi_free(help);
2800 if (!SUCCEEDED(res))
2801 ERR("Failed to register type library %s\n",
2802 debugstr_w(tl_struct.path));
2803 else
2805 ui_actiondata(package,szRegisterTypeLibraries,row);
2807 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2810 ITypeLib_Release(tl_struct.ptLib);
2811 msi_free(tl_struct.path);
2813 else
2814 ERR("Failed to load type library %s\n",
2815 debugstr_w(tl_struct.source));
2817 FreeLibrary(module);
2818 msi_free(tl_struct.source);
2820 else
2821 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2823 return ERROR_SUCCESS;
2826 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2829 * OK this is a bit confusing.. I am given a _Component key and I believe
2830 * that the file that is being registered as a type library is the "key file
2831 * of that component" which I interpret to mean "The file in the KeyPath of
2832 * that component".
2834 UINT rc;
2835 MSIQUERY * view;
2836 static const WCHAR Query[] =
2837 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2838 '`','T','y','p','e','L','i','b','`',0};
2840 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2841 if (rc != ERROR_SUCCESS)
2842 return ERROR_SUCCESS;
2844 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2845 msiobj_release(&view->hdr);
2846 return rc;
2849 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2851 MSIPACKAGE *package = (MSIPACKAGE*)param;
2852 LPWSTR target_file, target_folder, filename;
2853 LPCWSTR buffer;
2854 MSICOMPONENT *comp;
2855 static const WCHAR szlnk[]={'.','l','n','k',0};
2856 IShellLinkW *sl;
2857 IPersistFile *pf;
2858 HRESULT res;
2860 buffer = MSI_RecordGetString(row,4);
2861 comp = get_loaded_component(package,buffer);
2862 if (!comp)
2863 return ERROR_SUCCESS;
2865 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2867 TRACE("Skipping shortcut creation due to disabled component\n");
2869 comp->Action = comp->Installed;
2871 return ERROR_SUCCESS;
2874 comp->Action = INSTALLSTATE_LOCAL;
2876 ui_actiondata(package,szCreateShortcuts,row);
2878 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2879 &IID_IShellLinkW, (LPVOID *) &sl );
2881 if (FAILED(res))
2883 ERR("Is IID_IShellLink\n");
2884 return ERROR_SUCCESS;
2887 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2888 if( FAILED( res ) )
2890 ERR("Is IID_IPersistFile\n");
2891 return ERROR_SUCCESS;
2894 buffer = MSI_RecordGetString(row,2);
2895 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2897 /* may be needed because of a bug somehwere else */
2898 create_full_pathW(target_folder);
2900 filename = msi_dup_record_field( row, 3 );
2901 reduce_to_longfilename(filename);
2902 if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
2903 strcatW(filename,szlnk);
2904 target_file = build_directory_name(2, target_folder, filename);
2905 msi_free(target_folder);
2906 msi_free(filename);
2908 buffer = MSI_RecordGetString(row,5);
2909 if (strchrW(buffer,'['))
2911 LPWSTR deformated;
2912 deformat_string(package,buffer,&deformated);
2913 IShellLinkW_SetPath(sl,deformated);
2914 msi_free(deformated);
2916 else
2918 FIXME("poorly handled shortcut format, advertised shortcut\n");
2919 IShellLinkW_SetPath(sl,comp->FullKeypath);
2922 if (!MSI_RecordIsNull(row,6))
2924 LPWSTR deformated;
2925 buffer = MSI_RecordGetString(row,6);
2926 deformat_string(package,buffer,&deformated);
2927 IShellLinkW_SetArguments(sl,deformated);
2928 msi_free(deformated);
2931 if (!MSI_RecordIsNull(row,7))
2933 buffer = MSI_RecordGetString(row,7);
2934 IShellLinkW_SetDescription(sl,buffer);
2937 if (!MSI_RecordIsNull(row,8))
2938 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2940 if (!MSI_RecordIsNull(row,9))
2942 LPWSTR Path;
2943 INT index;
2945 buffer = MSI_RecordGetString(row,9);
2947 Path = build_icon_path(package,buffer);
2948 index = MSI_RecordGetInteger(row,10);
2950 IShellLinkW_SetIconLocation(sl,Path,index);
2951 msi_free(Path);
2954 if (!MSI_RecordIsNull(row,11))
2955 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2957 if (!MSI_RecordIsNull(row,12))
2959 LPWSTR Path;
2960 buffer = MSI_RecordGetString(row,12);
2961 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2962 IShellLinkW_SetWorkingDirectory(sl,Path);
2963 msi_free(Path);
2966 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2967 IPersistFile_Save(pf,target_file,FALSE);
2969 msi_free(target_file);
2971 IPersistFile_Release( pf );
2972 IShellLinkW_Release( sl );
2974 return ERROR_SUCCESS;
2977 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2979 UINT rc;
2980 HRESULT res;
2981 MSIQUERY * view;
2982 static const WCHAR Query[] =
2983 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2984 '`','S','h','o','r','t','c','u','t','`',0};
2986 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2987 if (rc != ERROR_SUCCESS)
2988 return ERROR_SUCCESS;
2990 res = CoInitialize( NULL );
2991 if (FAILED (res))
2993 ERR("CoInitialize failed\n");
2994 return ERROR_FUNCTION_FAILED;
2997 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2998 msiobj_release(&view->hdr);
3000 CoUninitialize();
3002 return rc;
3005 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3007 MSIPACKAGE* package = (MSIPACKAGE*)param;
3008 HANDLE the_file;
3009 LPWSTR FilePath;
3010 LPCWSTR FileName;
3011 CHAR buffer[1024];
3012 DWORD sz;
3013 UINT rc;
3015 FileName = MSI_RecordGetString(row,1);
3016 if (!FileName)
3018 ERR("Unable to get FileName\n");
3019 return ERROR_SUCCESS;
3022 FilePath = build_icon_path(package,FileName);
3024 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3026 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3027 FILE_ATTRIBUTE_NORMAL, NULL);
3029 if (the_file == INVALID_HANDLE_VALUE)
3031 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3032 msi_free(FilePath);
3033 return ERROR_SUCCESS;
3038 DWORD write;
3039 sz = 1024;
3040 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3041 if (rc != ERROR_SUCCESS)
3043 ERR("Failed to get stream\n");
3044 CloseHandle(the_file);
3045 DeleteFileW(FilePath);
3046 break;
3048 WriteFile(the_file,buffer,sz,&write,NULL);
3049 } while (sz == 1024);
3051 msi_free(FilePath);
3053 CloseHandle(the_file);
3054 return ERROR_SUCCESS;
3058 * 99% of the work done here is only done for
3059 * advertised installs. However this is where the
3060 * Icon table is processed and written out
3061 * so that is what I am going to do here.
3063 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3065 UINT rc;
3066 MSIQUERY * view;
3067 static const WCHAR Query[]=
3068 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3069 '`','I','c','o','n','`',0};
3070 /* for registry stuff */
3071 HKEY hkey=0;
3072 HKEY hukey=0;
3073 static const WCHAR szProductLanguage[] =
3074 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3075 static const WCHAR szARPProductIcon[] =
3076 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3077 static const WCHAR szProductVersion[] =
3078 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3079 DWORD langid;
3080 LPWSTR buffer;
3081 DWORD size;
3082 MSIHANDLE hDb, hSumInfo;
3084 /* write out icon files */
3086 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3087 if (rc == ERROR_SUCCESS)
3089 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3090 msiobj_release(&view->hdr);
3093 /* ok there is a lot more done here but i need to figure out what */
3095 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3096 if (rc != ERROR_SUCCESS)
3097 goto end;
3099 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3100 if (rc != ERROR_SUCCESS)
3101 goto end;
3104 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3105 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3106 msi_free(buffer);
3108 langid = msi_get_property_int( package, szProductLanguage, 0 );
3109 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3111 buffer = msi_dup_property( package, szARPProductIcon );
3112 if (buffer)
3114 LPWSTR path = build_icon_path(package,buffer);
3115 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3116 msi_free( path );
3118 msi_free(buffer);
3120 buffer = msi_dup_property( package, szProductVersion );
3121 if (buffer)
3123 DWORD verdword = build_version_dword(buffer);
3124 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3126 msi_free(buffer);
3128 /* FIXME: Need to write more keys to the user registry */
3130 hDb= alloc_msihandle( &package->db->hdr );
3131 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3132 MsiCloseHandle(hDb);
3133 if (rc == ERROR_SUCCESS)
3135 WCHAR guidbuffer[0x200];
3136 size = 0x200;
3137 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3138 guidbuffer, &size);
3139 if (rc == ERROR_SUCCESS)
3141 WCHAR squashed[GUID_SIZE];
3142 /* for now we only care about the first guid */
3143 LPWSTR ptr = strchrW(guidbuffer,';');
3144 if (ptr) *ptr = 0;
3145 squash_guid(guidbuffer,squashed);
3146 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3148 else
3150 ERR("Unable to query Revision_Number...\n");
3151 rc = ERROR_SUCCESS;
3153 MsiCloseHandle(hSumInfo);
3155 else
3157 ERR("Unable to open Summary Information\n");
3158 rc = ERROR_SUCCESS;
3161 end:
3163 RegCloseKey(hkey);
3164 RegCloseKey(hukey);
3166 return rc;
3169 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3171 MSIPACKAGE *package = (MSIPACKAGE*)param;
3172 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3173 LPWSTR deformated_section, deformated_key, deformated_value;
3174 LPWSTR folder, fullname = NULL;
3175 MSIRECORD * uirow;
3176 INT action;
3177 MSICOMPONENT *comp;
3178 static const WCHAR szWindowsFolder[] =
3179 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3181 component = MSI_RecordGetString(row, 8);
3182 comp = get_loaded_component(package,component);
3184 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3186 TRACE("Skipping ini file due to disabled component %s\n",
3187 debugstr_w(component));
3189 comp->Action = comp->Installed;
3191 return ERROR_SUCCESS;
3194 comp->Action = INSTALLSTATE_LOCAL;
3196 identifier = MSI_RecordGetString(row,1);
3197 filename = MSI_RecordGetString(row,2);
3198 dirproperty = MSI_RecordGetString(row,3);
3199 section = MSI_RecordGetString(row,4);
3200 key = MSI_RecordGetString(row,5);
3201 value = MSI_RecordGetString(row,6);
3202 action = MSI_RecordGetInteger(row,7);
3204 deformat_string(package,section,&deformated_section);
3205 deformat_string(package,key,&deformated_key);
3206 deformat_string(package,value,&deformated_value);
3208 if (dirproperty)
3210 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3211 if (!folder)
3212 folder = msi_dup_property( package, dirproperty );
3214 else
3215 folder = msi_dup_property( package, szWindowsFolder );
3217 if (!folder)
3219 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3220 goto cleanup;
3223 fullname = build_directory_name(2, folder, filename);
3225 if (action == 0)
3227 TRACE("Adding value %s to section %s in %s\n",
3228 debugstr_w(deformated_key), debugstr_w(deformated_section),
3229 debugstr_w(fullname));
3230 WritePrivateProfileStringW(deformated_section, deformated_key,
3231 deformated_value, fullname);
3233 else if (action == 1)
3235 WCHAR returned[10];
3236 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3237 returned, 10, fullname);
3238 if (returned[0] == 0)
3240 TRACE("Adding value %s to section %s in %s\n",
3241 debugstr_w(deformated_key), debugstr_w(deformated_section),
3242 debugstr_w(fullname));
3244 WritePrivateProfileStringW(deformated_section, deformated_key,
3245 deformated_value, fullname);
3248 else if (action == 3)
3249 FIXME("Append to existing section not yet implemented\n");
3251 uirow = MSI_CreateRecord(4);
3252 MSI_RecordSetStringW(uirow,1,identifier);
3253 MSI_RecordSetStringW(uirow,2,deformated_section);
3254 MSI_RecordSetStringW(uirow,3,deformated_key);
3255 MSI_RecordSetStringW(uirow,4,deformated_value);
3256 ui_actiondata(package,szWriteIniValues,uirow);
3257 msiobj_release( &uirow->hdr );
3258 cleanup:
3259 msi_free(fullname);
3260 msi_free(folder);
3261 msi_free(deformated_key);
3262 msi_free(deformated_value);
3263 msi_free(deformated_section);
3264 return ERROR_SUCCESS;
3267 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3269 UINT rc;
3270 MSIQUERY * view;
3271 static const WCHAR ExecSeqQuery[] =
3272 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3273 '`','I','n','i','F','i','l','e','`',0};
3275 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3276 if (rc != ERROR_SUCCESS)
3278 TRACE("no IniFile table\n");
3279 return ERROR_SUCCESS;
3282 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3283 msiobj_release(&view->hdr);
3284 return rc;
3287 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3289 MSIPACKAGE *package = (MSIPACKAGE*)param;
3290 LPCWSTR filename;
3291 LPWSTR FullName;
3292 MSIFILE *file;
3293 DWORD len;
3294 static const WCHAR ExeStr[] =
3295 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3296 static const WCHAR close[] = {'\"',0};
3297 STARTUPINFOW si;
3298 PROCESS_INFORMATION info;
3299 BOOL brc;
3301 memset(&si,0,sizeof(STARTUPINFOW));
3303 filename = MSI_RecordGetString(row,1);
3304 file = get_loaded_file( package, filename );
3306 if (!file)
3308 ERR("Unable to find file id %s\n",debugstr_w(filename));
3309 return ERROR_SUCCESS;
3312 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3314 FullName = msi_alloc(len*sizeof(WCHAR));
3315 strcpyW(FullName,ExeStr);
3316 strcatW( FullName, file->TargetPath );
3317 strcatW(FullName,close);
3319 TRACE("Registering %s\n",debugstr_w(FullName));
3320 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3321 &si, &info);
3323 if (brc)
3324 msi_dialog_check_messages(info.hProcess);
3326 msi_free(FullName);
3327 return ERROR_SUCCESS;
3330 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3332 UINT rc;
3333 MSIQUERY * view;
3334 static const WCHAR ExecSeqQuery[] =
3335 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3336 '`','S','e','l','f','R','e','g','`',0};
3338 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3339 if (rc != ERROR_SUCCESS)
3341 TRACE("no SelfReg table\n");
3342 return ERROR_SUCCESS;
3345 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3346 msiobj_release(&view->hdr);
3348 return ERROR_SUCCESS;
3351 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3353 MSIFEATURE *feature;
3354 UINT rc;
3355 HKEY hkey=0;
3356 HKEY hukey=0;
3358 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3359 if (rc != ERROR_SUCCESS)
3360 goto end;
3362 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3363 if (rc != ERROR_SUCCESS)
3364 goto end;
3366 /* here the guids are base 85 encoded */
3367 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3369 ComponentList *cl;
3370 LPWSTR data = NULL;
3371 GUID clsid;
3372 INT size;
3373 BOOL absent = FALSE;
3375 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3376 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3377 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3378 absent = TRUE;
3380 size = 1;
3381 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3383 size += 21;
3385 if (feature->Feature_Parent)
3386 size += strlenW( feature->Feature_Parent )+2;
3388 data = msi_alloc(size * sizeof(WCHAR));
3390 data[0] = 0;
3391 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3393 MSICOMPONENT* component = cl->component;
3394 WCHAR buf[21];
3396 memset(buf,0,sizeof(buf));
3397 if (component->ComponentId)
3399 TRACE("From %s\n",debugstr_w(component->ComponentId));
3400 CLSIDFromString(component->ComponentId, &clsid);
3401 encode_base85_guid(&clsid,buf);
3402 TRACE("to %s\n",debugstr_w(buf));
3403 strcatW(data,buf);
3406 if (feature->Feature_Parent)
3408 static const WCHAR sep[] = {'\2',0};
3409 strcatW(data,sep);
3410 strcatW(data,feature->Feature_Parent);
3413 msi_reg_set_val_str( hkey, feature->Feature, data );
3414 msi_free(data);
3416 size = 0;
3417 if (feature->Feature_Parent)
3418 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3419 if (!absent)
3421 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3422 (LPBYTE)feature->Feature_Parent,size);
3424 else
3426 size += 2*sizeof(WCHAR);
3427 data = msi_alloc(size);
3428 data[0] = 0x6;
3429 data[1] = 0;
3430 if (feature->Feature_Parent)
3431 strcpyW( &data[1], feature->Feature_Parent );
3432 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3433 (LPBYTE)data,size);
3434 msi_free(data);
3438 end:
3439 RegCloseKey(hkey);
3440 RegCloseKey(hukey);
3441 return rc;
3444 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3446 static const WCHAR installerPathFmt[] = {
3447 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3448 static const WCHAR fmt[] = {
3449 '%','s','\\',
3450 'I','n','s','t','a','l','l','e','r','\\',
3451 '%','x','.','m','s','i',0};
3452 static const WCHAR szOriginalDatabase[] =
3453 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3454 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3455 INT num, start;
3456 LPWSTR msiFilePath;
3457 BOOL r;
3459 /* copy the package locally */
3460 num = GetTickCount() & 0xffff;
3461 if (!num)
3462 num = 1;
3463 start = num;
3464 GetWindowsDirectoryW( windir, MAX_PATH );
3465 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3468 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3469 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3470 if (handle != INVALID_HANDLE_VALUE)
3472 CloseHandle(handle);
3473 break;
3475 if (GetLastError() != ERROR_FILE_EXISTS &&
3476 GetLastError() != ERROR_SHARING_VIOLATION)
3477 break;
3478 if (!(++num & 0xffff)) num = 1;
3479 sprintfW(packagefile,fmt,num);
3480 } while (num != start);
3482 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3483 create_full_pathW(path);
3485 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3487 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3488 r = CopyFileW( msiFilePath, packagefile, FALSE);
3489 msi_free( msiFilePath );
3491 if (!r)
3493 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3494 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3495 return ERROR_FUNCTION_FAILED;
3498 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3499 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3500 return ERROR_SUCCESS;
3503 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3505 LPWSTR prop, val, key;
3506 static const LPCSTR propval[] = {
3507 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3508 "ARPCONTACT", "Contact",
3509 "ARPCOMMENTS", "Comments",
3510 "ProductName", "DisplayName",
3511 "ProductVersion", "DisplayVersion",
3512 "ARPHELPLINK", "HelpLink",
3513 "ARPHELPTELEPHONE", "HelpTelephone",
3514 "ARPINSTALLLOCATION", "InstallLocation",
3515 "SourceDir", "InstallSource",
3516 "Manufacturer", "Publisher",
3517 "ARPREADME", "Readme",
3518 "ARPSIZE", "Size",
3519 "ARPURLINFOABOUT", "URLInfoAbout",
3520 "ARPURLUPDATEINFO", "URLUpdateInfo",
3521 NULL,
3523 const LPCSTR *p = propval;
3525 while( *p )
3527 prop = strdupAtoW( *p++ );
3528 key = strdupAtoW( *p++ );
3529 val = msi_dup_property( package, prop );
3530 msi_reg_set_val_str( hkey, key, val );
3531 msi_free(val);
3532 msi_free(key);
3533 msi_free(prop);
3535 return ERROR_SUCCESS;
3538 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3540 HKEY hkey=0;
3541 LPWSTR buffer = NULL;
3542 UINT rc;
3543 DWORD size, langid;
3544 static const WCHAR szWindowsInstaller[] =
3545 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3546 static const WCHAR szUpgradeCode[] =
3547 {'U','p','g','r','a','d','e','C','o','d','e',0};
3548 static const WCHAR modpath_fmt[] =
3549 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3550 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3551 static const WCHAR szModifyPath[] =
3552 {'M','o','d','i','f','y','P','a','t','h',0};
3553 static const WCHAR szUninstallString[] =
3554 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3555 static const WCHAR szEstimatedSize[] =
3556 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3557 static const WCHAR szProductLanguage[] =
3558 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3559 static const WCHAR szProductVersion[] =
3560 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3562 SYSTEMTIME systime;
3563 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3564 LPWSTR upgrade_code;
3565 WCHAR szDate[9];
3567 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3568 if (rc != ERROR_SUCCESS)
3569 return rc;
3571 /* dump all the info i can grab */
3572 /* FIXME: Flesh out more information */
3574 msi_write_uninstall_property_vals( package, hkey );
3576 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3578 msi_make_package_local( package, hkey );
3580 /* do ModifyPath and UninstallString */
3581 size = deformat_string(package,modpath_fmt,&buffer);
3582 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3583 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3584 msi_free(buffer);
3586 /* FIXME: Write real Estimated Size when we have it */
3587 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3589 GetLocalTime(&systime);
3590 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3591 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3593 langid = msi_get_property_int( package, szProductLanguage, 0 );
3594 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3596 buffer = msi_dup_property( package, szProductVersion );
3597 if (buffer)
3599 DWORD verdword = build_version_dword(buffer);
3601 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3602 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3603 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3605 msi_free(buffer);
3607 /* Handle Upgrade Codes */
3608 upgrade_code = msi_dup_property( package, szUpgradeCode );
3609 if (upgrade_code)
3611 HKEY hkey2;
3612 WCHAR squashed[33];
3613 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3614 squash_guid(package->ProductCode,squashed);
3615 msi_reg_set_val_str( hkey2, squashed, NULL );
3616 RegCloseKey(hkey2);
3617 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3618 squash_guid(package->ProductCode,squashed);
3619 msi_reg_set_val_str( hkey2, squashed, NULL );
3620 RegCloseKey(hkey2);
3622 msi_free(upgrade_code);
3625 RegCloseKey(hkey);
3627 return ERROR_SUCCESS;
3630 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3632 return execute_script(package,INSTALL_SCRIPT);
3635 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3637 UINT rc;
3639 /* turn off scheduleing */
3640 package->script->CurrentlyScripting= FALSE;
3642 /* first do the same as an InstallExecute */
3643 rc = ACTION_InstallExecute(package);
3644 if (rc != ERROR_SUCCESS)
3645 return rc;
3647 /* then handle Commit Actions */
3648 rc = execute_script(package,COMMIT_SCRIPT);
3650 return rc;
3653 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3655 static const WCHAR RunOnce[] = {
3656 'S','o','f','t','w','a','r','e','\\',
3657 'M','i','c','r','o','s','o','f','t','\\',
3658 'W','i','n','d','o','w','s','\\',
3659 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3660 'R','u','n','O','n','c','e',0};
3661 static const WCHAR InstallRunOnce[] = {
3662 'S','o','f','t','w','a','r','e','\\',
3663 'M','i','c','r','o','s','o','f','t','\\',
3664 'W','i','n','d','o','w','s','\\',
3665 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3666 'I','n','s','t','a','l','l','e','r','\\',
3667 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3669 static const WCHAR msiexec_fmt[] = {
3670 '%','s',
3671 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3672 '\"','%','s','\"',0};
3673 static const WCHAR install_fmt[] = {
3674 '/','I',' ','\"','%','s','\"',' ',
3675 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3676 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3677 WCHAR buffer[256], sysdir[MAX_PATH];
3678 HKEY hkey;
3679 WCHAR squished_pc[100];
3681 squash_guid(package->ProductCode,squished_pc);
3683 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3684 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3685 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3686 squished_pc);
3688 msi_reg_set_val_str( hkey, squished_pc, buffer );
3689 RegCloseKey(hkey);
3691 TRACE("Reboot command %s\n",debugstr_w(buffer));
3693 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3694 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3696 msi_reg_set_val_str( hkey, squished_pc, buffer );
3697 RegCloseKey(hkey);
3699 return ERROR_INSTALL_SUSPEND;
3702 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3704 DWORD attrib;
3705 UINT rc;
3707 * we are currently doing what should be done here in the top level Install
3708 * however for Adminastrative and uninstalls this step will be needed
3710 if (!package->PackagePath)
3711 return ERROR_SUCCESS;
3713 attrib = GetFileAttributesW(package->PackagePath);
3714 if (attrib == INVALID_FILE_ATTRIBUTES)
3716 LPWSTR prompt;
3717 LPWSTR msg;
3718 DWORD size = 0;
3720 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3721 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3722 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3723 if (rc == ERROR_MORE_DATA)
3725 prompt = msi_alloc(size * sizeof(WCHAR));
3726 MsiSourceListGetInfoW(package->ProductCode, NULL,
3727 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3728 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3730 else
3731 prompt = strdupW(package->PackagePath);
3733 msg = generate_error_string(package,1302,1,prompt);
3734 while(attrib == INVALID_FILE_ATTRIBUTES)
3736 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3737 if (rc == IDCANCEL)
3739 rc = ERROR_INSTALL_USEREXIT;
3740 break;
3742 attrib = GetFileAttributesW(package->PackagePath);
3744 msi_free(prompt);
3745 rc = ERROR_SUCCESS;
3747 else
3748 return ERROR_SUCCESS;
3750 return rc;
3753 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3755 HKEY hkey=0;
3756 LPWSTR buffer;
3757 LPWSTR productid;
3758 UINT rc,i;
3760 static const WCHAR szPropKeys[][80] =
3762 {'P','r','o','d','u','c','t','I','D',0},
3763 {'U','S','E','R','N','A','M','E',0},
3764 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3765 {0},
3768 static const WCHAR szRegKeys[][80] =
3770 {'P','r','o','d','u','c','t','I','D',0},
3771 {'R','e','g','O','w','n','e','r',0},
3772 {'R','e','g','C','o','m','p','a','n','y',0},
3773 {0},
3776 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3777 if (!productid)
3778 return ERROR_SUCCESS;
3780 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3781 if (rc != ERROR_SUCCESS)
3782 goto end;
3784 for( i = 0; szPropKeys[i][0]; i++ )
3786 buffer = msi_dup_property( package, szPropKeys[i] );
3787 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3788 msi_free( buffer );
3791 end:
3792 msi_free(productid);
3793 RegCloseKey(hkey);
3795 return ERROR_SUCCESS;
3799 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3801 UINT rc;
3803 package->script->InWhatSequence |= SEQUENCE_EXEC;
3804 rc = ACTION_ProcessExecSequence(package,FALSE);
3805 return rc;
3810 * Code based off of code located here
3811 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3813 * Using string index 4 (full font name) instead of 1 (family name)
3815 static LPWSTR load_ttfname_from(LPCWSTR filename)
3817 HANDLE handle;
3818 LPWSTR ret = NULL;
3819 int i;
3821 typedef struct _tagTT_OFFSET_TABLE{
3822 USHORT uMajorVersion;
3823 USHORT uMinorVersion;
3824 USHORT uNumOfTables;
3825 USHORT uSearchRange;
3826 USHORT uEntrySelector;
3827 USHORT uRangeShift;
3828 }TT_OFFSET_TABLE;
3830 typedef struct _tagTT_TABLE_DIRECTORY{
3831 char szTag[4]; /* table name */
3832 ULONG uCheckSum; /* Check sum */
3833 ULONG uOffset; /* Offset from beginning of file */
3834 ULONG uLength; /* length of the table in bytes */
3835 }TT_TABLE_DIRECTORY;
3837 typedef struct _tagTT_NAME_TABLE_HEADER{
3838 USHORT uFSelector; /* format selector. Always 0 */
3839 USHORT uNRCount; /* Name Records count */
3840 USHORT uStorageOffset; /* Offset for strings storage,
3841 * from start of the table */
3842 }TT_NAME_TABLE_HEADER;
3844 typedef struct _tagTT_NAME_RECORD{
3845 USHORT uPlatformID;
3846 USHORT uEncodingID;
3847 USHORT uLanguageID;
3848 USHORT uNameID;
3849 USHORT uStringLength;
3850 USHORT uStringOffset; /* from start of storage area */
3851 }TT_NAME_RECORD;
3853 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3854 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3856 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3857 FILE_ATTRIBUTE_NORMAL, 0 );
3858 if (handle != INVALID_HANDLE_VALUE)
3860 TT_TABLE_DIRECTORY tblDir;
3861 BOOL bFound = FALSE;
3862 TT_OFFSET_TABLE ttOffsetTable;
3863 DWORD dwRead;
3865 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3866 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3867 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3868 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3870 if (ttOffsetTable.uMajorVersion != 1 ||
3871 ttOffsetTable.uMinorVersion != 0)
3872 return NULL;
3874 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3876 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3877 if (strncmp(tblDir.szTag,"name",4)==0)
3879 bFound = TRUE;
3880 tblDir.uLength = SWAPLONG(tblDir.uLength);
3881 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3882 break;
3886 if (bFound)
3888 TT_NAME_TABLE_HEADER ttNTHeader;
3889 TT_NAME_RECORD ttRecord;
3891 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3892 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3893 &dwRead,NULL);
3895 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3896 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3897 bFound = FALSE;
3898 for(i=0; i<ttNTHeader.uNRCount; i++)
3900 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3901 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3902 /* 4 is the Full Font Name */
3903 if(ttRecord.uNameID == 4)
3905 int nPos;
3906 LPSTR buf;
3907 static LPCSTR tt = " (TrueType)";
3909 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3910 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3911 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3912 SetFilePointer(handle, tblDir.uOffset +
3913 ttRecord.uStringOffset +
3914 ttNTHeader.uStorageOffset,
3915 NULL, FILE_BEGIN);
3916 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3917 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3918 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3919 if (strlen(buf) > 0)
3921 strcat(buf,tt);
3922 ret = strdupAtoW(buf);
3923 msi_free(buf);
3924 break;
3927 msi_free(buf);
3928 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3932 CloseHandle(handle);
3934 else
3935 ERR("Unable to open font file %s\n", debugstr_w(filename));
3937 TRACE("Returning fontname %s\n",debugstr_w(ret));
3938 return ret;
3941 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3943 MSIPACKAGE *package = (MSIPACKAGE*)param;
3944 LPWSTR name;
3945 LPCWSTR filename;
3946 MSIFILE *file;
3947 static const WCHAR regfont1[] =
3948 {'S','o','f','t','w','a','r','e','\\',
3949 'M','i','c','r','o','s','o','f','t','\\',
3950 'W','i','n','d','o','w','s',' ','N','T','\\',
3951 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3952 'F','o','n','t','s',0};
3953 static const WCHAR regfont2[] =
3954 {'S','o','f','t','w','a','r','e','\\',
3955 'M','i','c','r','o','s','o','f','t','\\',
3956 'W','i','n','d','o','w','s','\\',
3957 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3958 'F','o','n','t','s',0};
3959 HKEY hkey1;
3960 HKEY hkey2;
3962 filename = MSI_RecordGetString( row, 1 );
3963 file = get_loaded_file( package, filename );
3964 if (!file)
3966 ERR("Unable to load file\n");
3967 return ERROR_SUCCESS;
3970 /* check to make sure that component is installed */
3971 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3973 TRACE("Skipping: Component not scheduled for install\n");
3974 return ERROR_SUCCESS;
3977 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3978 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3980 if (MSI_RecordIsNull(row,2))
3981 name = load_ttfname_from( file->TargetPath );
3982 else
3983 name = msi_dup_record_field(row,2);
3985 if (name)
3987 msi_reg_set_val_str( hkey1, name, file->FileName );
3988 msi_reg_set_val_str( hkey2, name, file->FileName );
3991 msi_free(name);
3992 RegCloseKey(hkey1);
3993 RegCloseKey(hkey2);
3994 return ERROR_SUCCESS;
3997 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
3999 UINT rc;
4000 MSIQUERY * view;
4001 static const WCHAR ExecSeqQuery[] =
4002 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4003 '`','F','o','n','t','`',0};
4005 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4006 if (rc != ERROR_SUCCESS)
4008 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4009 return ERROR_SUCCESS;
4012 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4013 msiobj_release(&view->hdr);
4015 return ERROR_SUCCESS;
4018 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4020 MSIPACKAGE *package = (MSIPACKAGE*)param;
4021 LPCWSTR compgroupid=NULL;
4022 LPCWSTR feature=NULL;
4023 LPCWSTR text = NULL;
4024 LPCWSTR qualifier = NULL;
4025 LPCWSTR component = NULL;
4026 LPWSTR advertise = NULL;
4027 LPWSTR output = NULL;
4028 HKEY hkey;
4029 UINT rc = ERROR_SUCCESS;
4030 MSICOMPONENT *comp;
4031 DWORD sz = 0;
4033 component = MSI_RecordGetString(rec,3);
4034 comp = get_loaded_component(package,component);
4036 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4037 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4038 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4040 TRACE("Skipping: Component %s not scheduled for install\n",
4041 debugstr_w(component));
4043 return ERROR_SUCCESS;
4046 compgroupid = MSI_RecordGetString(rec,1);
4048 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4049 if (rc != ERROR_SUCCESS)
4050 goto end;
4052 text = MSI_RecordGetString(rec,4);
4053 qualifier = MSI_RecordGetString(rec,2);
4054 feature = MSI_RecordGetString(rec,5);
4056 advertise = create_component_advertise_string(package, comp, feature);
4058 sz = strlenW(advertise);
4060 if (text)
4061 sz += lstrlenW(text);
4063 sz+=3;
4064 sz *= sizeof(WCHAR);
4066 output = msi_alloc(sz);
4067 memset(output,0,sz);
4068 strcpyW(output,advertise);
4069 msi_free(advertise);
4071 if (text)
4072 strcatW(output,text);
4074 msi_reg_set_val_multi_str( hkey, qualifier, output );
4076 end:
4077 RegCloseKey(hkey);
4078 msi_free(output);
4080 return rc;
4084 * At present I am ignorning the advertised components part of this and only
4085 * focusing on the qualified component sets
4087 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4089 UINT rc;
4090 MSIQUERY * view;
4091 static const WCHAR ExecSeqQuery[] =
4092 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4093 '`','P','u','b','l','i','s','h',
4094 'C','o','m','p','o','n','e','n','t','`',0};
4096 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4097 if (rc != ERROR_SUCCESS)
4098 return ERROR_SUCCESS;
4100 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4101 msiobj_release(&view->hdr);
4103 return rc;
4106 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4107 LPCSTR action, LPCWSTR table )
4109 static const WCHAR query[] = {
4110 'S','E','L','E','C','T',' ','*',' ',
4111 'F','R','O','M',' ','`','%','s','`',0 };
4112 MSIQUERY *view = NULL;
4113 DWORD count = 0;
4114 UINT r;
4116 r = MSI_OpenQuery( package->db, &view, query, table );
4117 if (r == ERROR_SUCCESS)
4119 r = MSI_IterateRecords(view, &count, NULL, package);
4120 msiobj_release(&view->hdr);
4123 if (count)
4124 FIXME("%s -> %lu ignored %s table values\n",
4125 action, count, debugstr_w(table));
4127 return ERROR_SUCCESS;
4130 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4132 TRACE("%p\n", package);
4133 return ERROR_SUCCESS;
4136 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4138 static const WCHAR table[] =
4139 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4140 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4143 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4145 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4146 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4149 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4151 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4152 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4155 static UINT ACTION_BindImage( MSIPACKAGE *package )
4157 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4158 return msi_unimplemented_action_stub( package, "BindImage", table );
4161 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4163 static const WCHAR table[] = {
4164 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4165 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4168 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4170 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4171 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4174 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4176 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4177 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4180 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4182 static const WCHAR table[] = {
4183 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4184 return msi_unimplemented_action_stub( package, "InstallServices", table );
4187 static UINT ACTION_StartServices( MSIPACKAGE *package )
4189 static const WCHAR table[] = {
4190 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4191 return msi_unimplemented_action_stub( package, "StartServices", table );
4194 static UINT ACTION_StopServices( MSIPACKAGE *package )
4196 static const WCHAR table[] = {
4197 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4198 return msi_unimplemented_action_stub( package, "StopServices", table );
4201 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4203 static const WCHAR table[] = {
4204 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4205 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4208 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4210 static const WCHAR table[] = {
4211 'E','n','v','i','r','o','n','m','e','n','t',0 };
4212 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4215 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4217 static const WCHAR table[] = {
4218 'E','n','v','i','r','o','n','m','e','n','t',0 };
4219 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4222 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4224 static const WCHAR table[] = {
4225 'M','s','i','A','s','s','e','m','b','l','y',0 };
4226 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4229 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4231 static const WCHAR table[] = {
4232 'M','s','i','A','s','s','e','m','b','l','y',0 };
4233 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4236 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4238 static const WCHAR table[] = { 'F','o','n','t',0 };
4239 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4242 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4244 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4245 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4248 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4250 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4251 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4254 static struct _actions StandardActions[] = {
4255 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4256 { szAppSearch, ACTION_AppSearch },
4257 { szBindImage, ACTION_BindImage },
4258 { szCCPSearch, ACTION_CCPSearch},
4259 { szCostFinalize, ACTION_CostFinalize },
4260 { szCostInitialize, ACTION_CostInitialize },
4261 { szCreateFolders, ACTION_CreateFolders },
4262 { szCreateShortcuts, ACTION_CreateShortcuts },
4263 { szDeleteServices, ACTION_DeleteServices },
4264 { szDisableRollback, NULL},
4265 { szDuplicateFiles, ACTION_DuplicateFiles },
4266 { szExecuteAction, ACTION_ExecuteAction },
4267 { szFileCost, ACTION_FileCost },
4268 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4269 { szForceReboot, ACTION_ForceReboot },
4270 { szInstallAdminPackage, NULL},
4271 { szInstallExecute, ACTION_InstallExecute },
4272 { szInstallExecuteAgain, ACTION_InstallExecute },
4273 { szInstallFiles, ACTION_InstallFiles},
4274 { szInstallFinalize, ACTION_InstallFinalize },
4275 { szInstallInitialize, ACTION_InstallInitialize },
4276 { szInstallSFPCatalogFile, NULL},
4277 { szInstallValidate, ACTION_InstallValidate },
4278 { szIsolateComponents, ACTION_IsolateComponents },
4279 { szLaunchConditions, ACTION_LaunchConditions },
4280 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4281 { szMoveFiles, ACTION_MoveFiles },
4282 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4283 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4284 { szInstallODBC, NULL},
4285 { szInstallServices, ACTION_InstallServices },
4286 { szPatchFiles, ACTION_PatchFiles },
4287 { szProcessComponents, ACTION_ProcessComponents },
4288 { szPublishComponents, ACTION_PublishComponents },
4289 { szPublishFeatures, ACTION_PublishFeatures },
4290 { szPublishProduct, ACTION_PublishProduct },
4291 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4292 { szRegisterComPlus, NULL},
4293 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4294 { szRegisterFonts, ACTION_RegisterFonts },
4295 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4296 { szRegisterProduct, ACTION_RegisterProduct },
4297 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4298 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4299 { szRegisterUser, ACTION_RegisterUser},
4300 { szRemoveDuplicateFiles, NULL},
4301 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4302 { szRemoveExistingProducts, NULL},
4303 { szRemoveFiles, ACTION_RemoveFiles},
4304 { szRemoveFolders, NULL},
4305 { szRemoveIniValues, ACTION_RemoveIniValues },
4306 { szRemoveODBC, NULL},
4307 { szRemoveRegistryValues, NULL},
4308 { szRemoveShortcuts, NULL},
4309 { szResolveSource, ACTION_ResolveSource},
4310 { szRMCCPSearch, ACTION_RMCCPSearch},
4311 { szScheduleReboot, NULL},
4312 { szSelfRegModules, ACTION_SelfRegModules },
4313 { szSelfUnregModules, ACTION_SelfUnregModules },
4314 { szSetODBCFolders, NULL},
4315 { szStartServices, ACTION_StartServices },
4316 { szStopServices, ACTION_StopServices },
4317 { szUnpublishComponents, NULL},
4318 { szUnpublishFeatures, NULL},
4319 { szUnregisterClassInfo, NULL},
4320 { szUnregisterComPlus, NULL},
4321 { szUnregisterExtensionInfo, NULL},
4322 { szUnregisterFonts, ACTION_UnregisterFonts },
4323 { szUnregisterMIMEInfo, NULL},
4324 { szUnregisterProgIdInfo, NULL},
4325 { szUnregisterTypeLibraries, NULL},
4326 { szValidateProductID, NULL},
4327 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4328 { szWriteIniValues, ACTION_WriteIniValues },
4329 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4330 { NULL, NULL},