wined3d: Add UpdatOverlayZOrder.
[wine.git] / dlls / msi / action.c
blobbe92b6f6c97cc3460e35d9479ee4cc163208927c
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238 struct _actions {
239 LPCWSTR action;
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
247 * helper functions
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
257 MSIRECORD * row;
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
260 if (!row)
261 return;
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
267 UINT rc)
269 MSIRECORD * row;
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272 '%','s', '.',0};
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276 '%','i','.',0};
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
279 WCHAR message[1024];
280 WCHAR timet[0x100];
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283 if (start)
284 sprintfW(message,template_s,timet,action);
285 else
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
297 LPCWSTR ptr,ptr2;
298 BOOL quote;
299 DWORD len;
300 LPWSTR prop = NULL, val = NULL;
302 if (!szCommandLine)
303 return ERROR_SUCCESS;
305 ptr = szCommandLine;
307 while (*ptr)
309 if (*ptr==' ')
311 ptr++;
312 continue;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
318 if (!ptr2)
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
321 break;
324 quote = FALSE;
326 len = ptr2-ptr;
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
329 prop[len]=0;
330 ptr2++;
332 len = 0;
333 ptr = ptr2;
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
336 if (*ptr == '"')
337 quote = !quote;
338 ptr++;
339 len++;
342 if (*ptr2=='"')
344 ptr2++;
345 len -= 2;
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
349 val[len] = 0;
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
357 msi_free(val);
358 msi_free(prop);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367 LPCWSTR pc;
368 LPWSTR p, *ret = NULL;
369 UINT count = 0;
371 if (!str)
372 return ret;
374 /* count the number of substrings */
375 for ( pc = str, count = 0; pc; count++ )
377 pc = strchrW( pc, sep );
378 if (pc)
379 pc++;
382 /* allocate space for an array of substring pointers and the substrings */
383 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384 (lstrlenW(str)+1) * sizeof(WCHAR) );
385 if (!ret)
386 return ret;
388 /* copy the string and set the pointers */
389 p = (LPWSTR) &ret[count+1];
390 lstrcpyW( p, str );
391 for( count = 0; (ret[count] = p); count++ )
393 p = strchrW( p, sep );
394 if (p)
395 *p++ = 0;
398 return ret;
401 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
402 MSIDATABASE *patch_db, LPCWSTR name )
404 UINT ret = ERROR_FUNCTION_FAILED;
405 IStorage *stg = NULL;
406 HRESULT r;
408 TRACE("%p %s\n", package, debugstr_w(name) );
410 if (*name++ != ':')
412 ERR("expected a colon in %s\n", debugstr_w(name));
413 return ERROR_FUNCTION_FAILED;
416 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
417 if (SUCCEEDED(r))
419 ret = msi_table_apply_transform( package->db, stg );
420 IStorage_Release( stg );
421 ret = ERROR_SUCCESS;
423 else
424 ERR("failed to open substorage %s\n", debugstr_w(name));
426 return ret;
429 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
431 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
432 LPWSTR guid_list, *guids, product_id;
433 UINT i, ret = ERROR_FUNCTION_FAILED;
435 product_id = msi_dup_property( package, szProdID );
436 if (!product_id)
438 /* FIXME: the property ProductID should be written into the DB somewhere */
439 ERR("no product ID to check\n");
440 return ERROR_SUCCESS;
443 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
444 guids = msi_split_string( guid_list, ';' );
445 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
447 if (!lstrcmpW( guids[i], product_id ))
448 ret = ERROR_SUCCESS;
450 msi_free( guids );
451 msi_free( guid_list );
452 msi_free( product_id );
454 return ret;
457 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
459 MSISUMMARYINFO *si;
460 LPWSTR str, *substorage;
461 UINT i, r = ERROR_SUCCESS;
463 si = MSI_GetSummaryInformationW( patch_db, 0 );
464 if (!si)
465 return ERROR_FUNCTION_FAILED;
467 msi_check_patch_applicable( package, si );
469 /* enumerate the substorage */
470 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
471 substorage = msi_split_string( str, ';' );
472 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
473 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
474 msi_free( substorage );
475 msi_free( str );
477 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
479 msiobj_release( &si->hdr );
481 return r;
484 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
486 MSIDATABASE *patch_db = NULL;
487 UINT r;
489 TRACE("%p %s\n", package, debugstr_w( file ) );
491 /* FIXME:
492 * We probably want to make sure we only open a patch collection here.
493 * Patch collections (.msp) and databases (.msi) have different GUIDs
494 * but currently MSI_OpenDatabaseW will accept both.
496 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
497 if ( r != ERROR_SUCCESS )
499 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
500 return r;
503 msi_parse_patch_summary( package, patch_db );
504 msiobj_release( &patch_db->hdr );
506 return ERROR_SUCCESS;
509 /* get the PATCH property, and apply all the patches it specifies */
510 static UINT msi_apply_patches( MSIPACKAGE *package )
512 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
513 LPWSTR patch_list, *patches;
514 UINT i, r = ERROR_SUCCESS;
516 patch_list = msi_dup_property( package, szPatch );
518 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
520 patches = msi_split_string( patch_list, ';' );
521 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
522 r = msi_apply_patch_package( package, patches[i] );
524 msi_free( patches );
525 msi_free( patch_list );
527 return r;
530 static UINT msi_apply_transforms( MSIPACKAGE *package )
532 static const WCHAR szTransforms[] = {
533 'T','R','A','N','S','F','O','R','M','S',0 };
534 LPWSTR xform_list, *xforms;
535 UINT i, r = ERROR_SUCCESS;
537 xform_list = msi_dup_property( package, szTransforms );
538 xforms = msi_split_string( xform_list, ';' );
540 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
542 if (xforms[i][0] == ':')
543 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
544 else
545 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
548 msi_free( xforms );
549 msi_free( xform_list );
551 return r;
554 /****************************************************
555 * TOP level entry points
556 *****************************************************/
558 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
559 LPCWSTR szCommandLine )
561 UINT rc;
562 BOOL ui = FALSE;
563 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
564 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
565 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
567 MSI_SetPropertyW(package, szAction, szInstall);
569 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
571 package->script->InWhatSequence = SEQUENCE_INSTALL;
573 if (szPackagePath)
575 LPWSTR p, check, path;
577 package->PackagePath = strdupW(szPackagePath);
578 path = strdupW(szPackagePath);
579 p = strrchrW(path,'\\');
580 if (p)
582 p++;
583 *p=0;
585 else
587 msi_free(path);
588 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
589 GetCurrentDirectoryW(MAX_PATH,path);
590 strcatW(path,cszbs);
593 check = msi_dup_property( package, cszSourceDir );
594 if (!check)
595 MSI_SetPropertyW(package, cszSourceDir, path);
596 msi_free(check);
597 msi_free(path);
600 msi_parse_command_line( package, szCommandLine );
602 msi_apply_transforms( package );
603 msi_apply_patches( package );
605 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
607 package->script->InWhatSequence |= SEQUENCE_UI;
608 rc = ACTION_ProcessUISequence(package);
609 ui = TRUE;
610 if (rc == ERROR_SUCCESS)
612 package->script->InWhatSequence |= SEQUENCE_EXEC;
613 rc = ACTION_ProcessExecSequence(package,TRUE);
616 else
617 rc = ACTION_ProcessExecSequence(package,FALSE);
619 if (rc == -1)
621 /* install was halted but should be considered a success */
622 rc = ERROR_SUCCESS;
625 package->script->CurrentlyScripting= FALSE;
627 /* process the ending type action */
628 if (rc == ERROR_SUCCESS)
629 ACTION_PerformActionSequence(package,-1,ui);
630 else if (rc == ERROR_INSTALL_USEREXIT)
631 ACTION_PerformActionSequence(package,-2,ui);
632 else if (rc == ERROR_INSTALL_SUSPEND)
633 ACTION_PerformActionSequence(package,-4,ui);
634 else /* failed */
635 ACTION_PerformActionSequence(package,-3,ui);
637 /* finish up running custom actions */
638 ACTION_FinishCustomActions(package);
640 return rc;
643 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
645 UINT rc = ERROR_SUCCESS;
646 MSIRECORD * row = 0;
647 static const WCHAR ExecSeqQuery[] =
648 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
649 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
650 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
651 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
653 static const WCHAR UISeqQuery[] =
654 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
655 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
656 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
657 ' ', '=',' ','%','i',0};
659 if (UI)
660 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
661 else
662 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
664 if (row)
666 LPCWSTR action, cond;
668 TRACE("Running the actions\n");
670 /* check conditions */
671 cond = MSI_RecordGetString(row,2);
672 if (cond)
674 /* this is a hack to skip errors in the condition code */
675 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
676 goto end;
679 action = MSI_RecordGetString(row,1);
680 if (!action)
682 ERR("failed to fetch action\n");
683 rc = ERROR_FUNCTION_FAILED;
684 goto end;
687 if (UI)
688 rc = ACTION_PerformUIAction(package,action);
689 else
690 rc = ACTION_PerformAction(package,action,FALSE);
691 end:
692 msiobj_release(&row->hdr);
694 else
695 rc = ERROR_SUCCESS;
697 return rc;
700 typedef struct {
701 MSIPACKAGE* package;
702 BOOL UI;
703 } iterate_action_param;
705 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
707 iterate_action_param *iap= (iterate_action_param*)param;
708 UINT rc;
709 LPCWSTR cond, action;
711 action = MSI_RecordGetString(row,1);
712 if (!action)
714 ERR("Error is retrieving action name\n");
715 return ERROR_FUNCTION_FAILED;
718 /* check conditions */
719 cond = MSI_RecordGetString(row,2);
720 if (cond)
722 /* this is a hack to skip errors in the condition code */
723 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
725 TRACE("Skipping action: %s (condition is false)\n",
726 debugstr_w(action));
727 return ERROR_SUCCESS;
731 if (iap->UI)
732 rc = ACTION_PerformUIAction(iap->package,action);
733 else
734 rc = ACTION_PerformAction(iap->package,action,FALSE);
736 msi_dialog_check_messages( NULL );
738 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
739 rc = iap->package->CurrentInstallState;
741 if (rc == ERROR_FUNCTION_NOT_CALLED)
742 rc = ERROR_SUCCESS;
744 if (rc != ERROR_SUCCESS)
745 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
747 return rc;
750 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
752 MSIQUERY * view;
753 UINT r;
754 static const WCHAR query[] =
755 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
756 '`','%','s','`',
757 ' ','W','H','E','R','E',' ',
758 '`','S','e','q','u','e','n','c','e','`',' ',
759 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
760 '`','S','e','q','u','e','n','c','e','`',0};
761 iterate_action_param iap;
764 * FIXME: probably should be checking UILevel in the
765 * ACTION_PerformUIAction/ACTION_PerformAction
766 * rather than saving the UI level here. Those
767 * two functions can be merged too.
769 iap.package = package;
770 iap.UI = TRUE;
772 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
774 r = MSI_OpenQuery( package->db, &view, query, szTable );
775 if (r == ERROR_SUCCESS)
777 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
778 msiobj_release(&view->hdr);
781 return r;
784 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
786 MSIQUERY * view;
787 UINT rc;
788 static const WCHAR ExecSeqQuery[] =
789 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
790 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
791 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
792 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
793 'O','R','D','E','R',' ', 'B','Y',' ',
794 '`','S','e','q','u','e','n','c','e','`',0 };
795 MSIRECORD * row = 0;
796 static const WCHAR IVQuery[] =
797 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
798 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
799 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
800 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
801 ' ','\'', 'I','n','s','t','a','l','l',
802 'V','a','l','i','d','a','t','e','\'', 0};
803 INT seq = 0;
804 iterate_action_param iap;
806 iap.package = package;
807 iap.UI = FALSE;
809 if (package->script->ExecuteSequenceRun)
811 TRACE("Execute Sequence already Run\n");
812 return ERROR_SUCCESS;
815 package->script->ExecuteSequenceRun = TRUE;
817 /* get the sequence number */
818 if (UIran)
820 row = MSI_QueryGetRecord(package->db, IVQuery);
821 if( !row )
822 return ERROR_FUNCTION_FAILED;
823 seq = MSI_RecordGetInteger(row,1);
824 msiobj_release(&row->hdr);
827 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
828 if (rc == ERROR_SUCCESS)
830 TRACE("Running the actions\n");
832 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
833 msiobj_release(&view->hdr);
836 return rc;
839 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
841 MSIQUERY * view;
842 UINT rc;
843 static const WCHAR ExecSeqQuery [] =
844 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
845 '`','I','n','s','t','a','l','l',
846 'U','I','S','e','q','u','e','n','c','e','`',
847 ' ','W','H','E','R','E',' ',
848 '`','S','e','q','u','e','n','c','e','`',' ',
849 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
850 '`','S','e','q','u','e','n','c','e','`',0};
851 iterate_action_param iap;
853 iap.package = package;
854 iap.UI = TRUE;
856 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
858 if (rc == ERROR_SUCCESS)
860 TRACE("Running the actions\n");
862 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
863 msiobj_release(&view->hdr);
866 return rc;
869 /********************************************************
870 * ACTION helper functions and functions that perform the actions
871 *******************************************************/
872 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
873 UINT* rc, BOOL force )
875 BOOL ret = FALSE;
876 BOOL run = force;
877 int i;
879 if (!run && !package->script->CurrentlyScripting)
880 run = TRUE;
882 if (!run)
884 if (strcmpW(action,szInstallFinalize) == 0 ||
885 strcmpW(action,szInstallExecute) == 0 ||
886 strcmpW(action,szInstallExecuteAgain) == 0)
887 run = TRUE;
890 i = 0;
891 while (StandardActions[i].action != NULL)
893 if (strcmpW(StandardActions[i].action, action)==0)
895 if (!run)
897 ui_actioninfo(package, action, TRUE, 0);
898 *rc = schedule_action(package,INSTALL_SCRIPT,action);
899 ui_actioninfo(package, action, FALSE, *rc);
901 else
903 ui_actionstart(package, action);
904 if (StandardActions[i].handler)
906 *rc = StandardActions[i].handler(package);
908 else
910 FIXME("unhandled standard action %s\n",debugstr_w(action));
911 *rc = ERROR_SUCCESS;
914 ret = TRUE;
915 break;
917 i++;
919 return ret;
922 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
923 UINT* rc, BOOL force )
925 BOOL ret=FALSE;
926 UINT arc;
928 arc = ACTION_CustomAction(package,action, force);
930 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
932 *rc = arc;
933 ret = TRUE;
935 return ret;
939 * A lot of actions are really important even if they don't do anything
940 * explicit... Lots of properties are set at the beginning of the installation
941 * CostFinalize does a bunch of work to translate the directories and such
943 * But until I get write access to the database that is hard, so I am going to
944 * hack it to see if I can get something to run.
946 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
948 UINT rc = ERROR_SUCCESS;
949 BOOL handled;
951 TRACE("Performing action (%s)\n",debugstr_w(action));
953 handled = ACTION_HandleStandardAction(package, action, &rc, force);
955 if (!handled)
956 handled = ACTION_HandleCustomAction(package, action, &rc, force);
958 if (!handled)
960 FIXME("unhandled msi action %s\n",debugstr_w(action));
961 rc = ERROR_FUNCTION_NOT_CALLED;
964 return rc;
967 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
969 UINT rc = ERROR_SUCCESS;
970 BOOL handled = FALSE;
972 TRACE("Performing action (%s)\n",debugstr_w(action));
974 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
976 if (!handled)
977 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
979 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
980 handled = TRUE;
982 if (!handled)
984 FIXME("unhandled msi action %s\n",debugstr_w(action));
985 rc = ERROR_FUNCTION_NOT_CALLED;
988 return rc;
993 * Actual Action Handlers
996 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
998 MSIPACKAGE *package = (MSIPACKAGE*)param;
999 LPCWSTR dir;
1000 LPWSTR full_path;
1001 MSIRECORD *uirow;
1002 MSIFOLDER *folder;
1004 dir = MSI_RecordGetString(row,1);
1005 if (!dir)
1007 ERR("Unable to get folder id\n");
1008 return ERROR_SUCCESS;
1011 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1012 if (!full_path)
1014 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1015 return ERROR_SUCCESS;
1018 TRACE("Folder is %s\n",debugstr_w(full_path));
1020 /* UI stuff */
1021 uirow = MSI_CreateRecord(1);
1022 MSI_RecordSetStringW(uirow,1,full_path);
1023 ui_actiondata(package,szCreateFolders,uirow);
1024 msiobj_release( &uirow->hdr );
1026 if (folder->State == 0)
1027 create_full_pathW(full_path);
1029 folder->State = 3;
1031 msi_free(full_path);
1032 return ERROR_SUCCESS;
1035 /* FIXME: probably should merge this with the above function */
1036 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1038 UINT rc = ERROR_SUCCESS;
1039 MSIFOLDER *folder;
1040 LPWSTR install_path;
1042 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1043 if (!install_path)
1044 return ERROR_FUNCTION_FAILED;
1046 /* create the path */
1047 if (folder->State == 0)
1049 create_full_pathW(install_path);
1050 folder->State = 2;
1052 msi_free(install_path);
1054 return rc;
1057 UINT msi_create_component_directories( MSIPACKAGE *package )
1059 MSICOMPONENT *comp;
1061 /* create all the folders required by the components are going to install */
1062 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1064 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1065 continue;
1066 msi_create_directory( package, comp->Directory );
1069 return ERROR_SUCCESS;
1073 * Also we cannot enable/disable components either, so for now I am just going
1074 * to do all the directories for all the components.
1076 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1078 static const WCHAR ExecSeqQuery[] =
1079 {'S','E','L','E','C','T',' ',
1080 '`','D','i','r','e','c','t','o','r','y','_','`',
1081 ' ','F','R','O','M',' ',
1082 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1083 UINT rc;
1084 MSIQUERY *view;
1086 /* create all the empty folders specified in the CreateFolder table */
1087 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1088 if (rc != ERROR_SUCCESS)
1089 return ERROR_SUCCESS;
1091 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1092 msiobj_release(&view->hdr);
1094 msi_create_component_directories( package );
1096 return rc;
1099 static UINT load_component( MSIRECORD *row, LPVOID param )
1101 MSIPACKAGE *package = param;
1102 MSICOMPONENT *comp;
1104 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1105 if (!comp)
1106 return ERROR_FUNCTION_FAILED;
1108 list_add_tail( &package->components, &comp->entry );
1110 /* fill in the data */
1111 comp->Component = msi_dup_record_field( row, 1 );
1113 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1115 comp->ComponentId = msi_dup_record_field( row, 2 );
1116 comp->Directory = msi_dup_record_field( row, 3 );
1117 comp->Attributes = MSI_RecordGetInteger(row,4);
1118 comp->Condition = msi_dup_record_field( row, 5 );
1119 comp->KeyPath = msi_dup_record_field( row, 6 );
1121 comp->Installed = INSTALLSTATE_UNKNOWN;
1122 comp->Action = INSTALLSTATE_UNKNOWN;
1123 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1125 return ERROR_SUCCESS;
1128 static UINT load_all_components( MSIPACKAGE *package )
1130 static const WCHAR query[] = {
1131 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1132 '`','C','o','m','p','o','n','e','n','t','`',0 };
1133 MSIQUERY *view;
1134 UINT r;
1136 if (!list_empty(&package->components))
1137 return ERROR_SUCCESS;
1139 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1140 if (r != ERROR_SUCCESS)
1141 return r;
1143 r = MSI_IterateRecords(view, NULL, load_component, package);
1144 msiobj_release(&view->hdr);
1145 return r;
1148 typedef struct {
1149 MSIPACKAGE *package;
1150 MSIFEATURE *feature;
1151 } _ilfs;
1153 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1155 ComponentList *cl;
1157 cl = msi_alloc( sizeof (*cl) );
1158 if ( !cl )
1159 return ERROR_NOT_ENOUGH_MEMORY;
1160 cl->component = comp;
1161 list_add_tail( &feature->Components, &cl->entry );
1163 return ERROR_SUCCESS;
1166 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1168 FeatureList *fl;
1170 fl = msi_alloc( sizeof(*fl) );
1171 if ( !fl )
1172 return ERROR_NOT_ENOUGH_MEMORY;
1173 fl->feature = child;
1174 list_add_tail( &parent->Children, &fl->entry );
1176 return ERROR_SUCCESS;
1179 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1181 _ilfs* ilfs= (_ilfs*)param;
1182 LPCWSTR component;
1183 MSICOMPONENT *comp;
1185 component = MSI_RecordGetString(row,1);
1187 /* check to see if the component is already loaded */
1188 comp = get_loaded_component( ilfs->package, component );
1189 if (!comp)
1191 ERR("unknown component %s\n", debugstr_w(component));
1192 return ERROR_FUNCTION_FAILED;
1195 add_feature_component( ilfs->feature, comp );
1196 comp->Enabled = TRUE;
1198 return ERROR_SUCCESS;
1201 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1203 MSIFEATURE *feature;
1205 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1207 if ( !lstrcmpW( feature->Feature, name ) )
1208 return feature;
1211 return NULL;
1214 static UINT load_feature(MSIRECORD * row, LPVOID param)
1216 MSIPACKAGE* package = (MSIPACKAGE*)param;
1217 MSIFEATURE* feature;
1218 static const WCHAR Query1[] =
1219 {'S','E','L','E','C','T',' ',
1220 '`','C','o','m','p','o','n','e','n','t','_','`',
1221 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1222 'C','o','m','p','o','n','e','n','t','s','`',' ',
1223 'W','H','E','R','E',' ',
1224 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1225 MSIQUERY * view;
1226 UINT rc;
1227 _ilfs ilfs;
1229 /* fill in the data */
1231 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1232 if (!feature)
1233 return ERROR_NOT_ENOUGH_MEMORY;
1235 list_init( &feature->Children );
1236 list_init( &feature->Components );
1238 feature->Feature = msi_dup_record_field( row, 1 );
1240 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1242 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1243 feature->Title = msi_dup_record_field( row, 3 );
1244 feature->Description = msi_dup_record_field( row, 4 );
1246 if (!MSI_RecordIsNull(row,5))
1247 feature->Display = MSI_RecordGetInteger(row,5);
1249 feature->Level= MSI_RecordGetInteger(row,6);
1250 feature->Directory = msi_dup_record_field( row, 7 );
1251 feature->Attributes = MSI_RecordGetInteger(row,8);
1253 feature->Installed = INSTALLSTATE_UNKNOWN;
1254 feature->Action = INSTALLSTATE_UNKNOWN;
1255 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1257 list_add_tail( &package->features, &feature->entry );
1259 /* load feature components */
1261 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1262 if (rc != ERROR_SUCCESS)
1263 return ERROR_SUCCESS;
1265 ilfs.package = package;
1266 ilfs.feature = feature;
1268 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1269 msiobj_release(&view->hdr);
1271 return ERROR_SUCCESS;
1274 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1276 MSIPACKAGE* package = (MSIPACKAGE*)param;
1277 MSIFEATURE *parent, *child;
1279 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1280 if (!child)
1281 return ERROR_FUNCTION_FAILED;
1283 if (!child->Feature_Parent)
1284 return ERROR_SUCCESS;
1286 parent = find_feature_by_name( package, child->Feature_Parent );
1287 if (!parent)
1288 return ERROR_FUNCTION_FAILED;
1290 add_feature_child( parent, child );
1291 return ERROR_SUCCESS;
1294 static UINT load_all_features( MSIPACKAGE *package )
1296 static const WCHAR query[] = {
1297 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1298 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1299 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1300 MSIQUERY *view;
1301 UINT r;
1303 if (!list_empty(&package->features))
1304 return ERROR_SUCCESS;
1306 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1307 if (r != ERROR_SUCCESS)
1308 return r;
1310 r = MSI_IterateRecords( view, NULL, load_feature, package );
1311 if (r != ERROR_SUCCESS)
1312 return r;
1314 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1315 msiobj_release( &view->hdr );
1317 return r;
1320 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1322 if (!p)
1323 return p;
1324 p = strchrW(p, ch);
1325 if (!p)
1326 return p;
1327 *p = 0;
1328 return p+1;
1331 static UINT load_file(MSIRECORD *row, LPVOID param)
1333 MSIPACKAGE* package = (MSIPACKAGE*)param;
1334 LPCWSTR component;
1335 MSIFILE *file;
1337 /* fill in the data */
1339 file = msi_alloc_zero( sizeof (MSIFILE) );
1340 if (!file)
1341 return ERROR_NOT_ENOUGH_MEMORY;
1343 file->File = msi_dup_record_field( row, 1 );
1345 component = MSI_RecordGetString( row, 2 );
1346 file->Component = get_loaded_component( package, component );
1348 if (!file->Component)
1349 ERR("Unfound Component %s\n",debugstr_w(component));
1351 file->FileName = msi_dup_record_field( row, 3 );
1352 reduce_to_longfilename( file->FileName );
1354 file->ShortName = msi_dup_record_field( row, 3 );
1355 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1357 file->FileSize = MSI_RecordGetInteger( row, 4 );
1358 file->Version = msi_dup_record_field( row, 5 );
1359 file->Language = msi_dup_record_field( row, 6 );
1360 file->Attributes = MSI_RecordGetInteger( row, 7 );
1361 file->Sequence = MSI_RecordGetInteger( row, 8 );
1363 file->state = msifs_invalid;
1365 /* if the compressed bits are not set in the file attributes,
1366 * then read the information from the package word count property
1368 if (file->Attributes & msidbFileAttributesCompressed)
1370 file->IsCompressed = TRUE;
1372 else if (file->Attributes & msidbFileAttributesNoncompressed)
1374 file->IsCompressed = FALSE;
1376 else
1378 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1381 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1383 list_add_tail( &package->files, &file->entry );
1385 return ERROR_SUCCESS;
1388 static UINT load_all_files(MSIPACKAGE *package)
1390 MSIQUERY * view;
1391 UINT rc;
1392 static const WCHAR Query[] =
1393 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1394 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1395 '`','S','e','q','u','e','n','c','e','`', 0};
1397 if (!list_empty(&package->files))
1398 return ERROR_SUCCESS;
1400 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1401 if (rc != ERROR_SUCCESS)
1402 return ERROR_SUCCESS;
1404 rc = MSI_IterateRecords(view, NULL, load_file, package);
1405 msiobj_release(&view->hdr);
1407 return ERROR_SUCCESS;
1412 * I am not doing any of the costing functionality yet.
1413 * Mostly looking at doing the Component and Feature loading
1415 * The native MSI does A LOT of modification to tables here. Mostly adding
1416 * a lot of temporary columns to the Feature and Component tables.
1418 * note: Native msi also tracks the short filename. But I am only going to
1419 * track the long ones. Also looking at this directory table
1420 * it appears that the directory table does not get the parents
1421 * resolved base on property only based on their entries in the
1422 * directory table.
1424 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1426 static const WCHAR szCosting[] =
1427 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1428 static const WCHAR szZero[] = { '0', 0 };
1430 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1431 return ERROR_SUCCESS;
1433 MSI_SetPropertyW(package, szCosting, szZero);
1434 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1436 load_all_components( package );
1437 load_all_features( package );
1438 load_all_files( package );
1440 return ERROR_SUCCESS;
1443 static UINT execute_script(MSIPACKAGE *package, UINT script )
1445 int i;
1446 UINT rc = ERROR_SUCCESS;
1448 TRACE("Executing Script %i\n",script);
1450 if (!package->script)
1452 ERR("no script!\n");
1453 return ERROR_FUNCTION_FAILED;
1456 for (i = 0; i < package->script->ActionCount[script]; i++)
1458 LPWSTR action;
1459 action = package->script->Actions[script][i];
1460 ui_actionstart(package, action);
1461 TRACE("Executing Action (%s)\n",debugstr_w(action));
1462 rc = ACTION_PerformAction(package, action, TRUE);
1463 msi_free(package->script->Actions[script][i]);
1464 if (rc != ERROR_SUCCESS)
1465 break;
1467 msi_free(package->script->Actions[script]);
1469 package->script->ActionCount[script] = 0;
1470 package->script->Actions[script] = NULL;
1471 return rc;
1474 static UINT ACTION_FileCost(MSIPACKAGE *package)
1476 return ERROR_SUCCESS;
1479 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1481 static const WCHAR Query[] =
1482 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1483 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1484 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1485 ' ','=',' ','\'','%','s','\'',
1487 static const WCHAR szDot[] = { '.',0 };
1488 static WCHAR szEmpty[] = { 0 };
1489 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1490 LPCWSTR parent;
1491 MSIRECORD *row;
1492 MSIFOLDER *folder;
1494 TRACE("Looking for dir %s\n",debugstr_w(dir));
1496 folder = get_loaded_folder( package, dir );
1497 if (folder)
1498 return folder;
1500 TRACE("Working to load %s\n",debugstr_w(dir));
1502 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1503 if (!folder)
1504 return NULL;
1506 folder->Directory = strdupW(dir);
1508 row = MSI_QueryGetRecord(package->db, Query, dir);
1509 if (!row)
1510 return NULL;
1512 p = msi_dup_record_field(row, 3);
1514 /* split src and target dir */
1515 tgt_short = p;
1516 src_short = folder_split_path( p, ':' );
1518 /* split the long and short paths */
1519 tgt_long = folder_split_path( tgt_short, '|' );
1520 src_long = folder_split_path( src_short, '|' );
1522 /* check for no-op dirs */
1523 if (!lstrcmpW(szDot, tgt_short))
1524 tgt_short = szEmpty;
1525 if (!lstrcmpW(szDot, src_short))
1526 src_short = szEmpty;
1528 if (!tgt_long)
1529 tgt_long = tgt_short;
1531 if (!src_short) {
1532 src_short = tgt_short;
1533 src_long = tgt_long;
1536 if (!src_long)
1537 src_long = src_short;
1539 /* FIXME: use the target short path too */
1540 folder->TargetDefault = strdupW(tgt_long);
1541 folder->SourceShortPath = strdupW(src_short);
1542 folder->SourceLongPath = strdupW(src_long);
1543 msi_free(p);
1545 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1546 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1547 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1549 parent = MSI_RecordGetString(row, 2);
1550 if (parent)
1552 folder->Parent = load_folder( package, parent );
1553 if ( folder->Parent )
1554 TRACE("loaded parent %p %s\n", folder->Parent,
1555 debugstr_w(folder->Parent->Directory));
1556 else
1557 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1560 folder->Property = msi_dup_property( package, dir );
1562 msiobj_release(&row->hdr);
1564 list_add_tail( &package->folders, &folder->entry );
1566 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1568 return folder;
1571 /* scan for and update current install states */
1572 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1574 MSICOMPONENT *comp;
1575 MSIFEATURE *feature;
1577 /* FIXME: component's installed state should be determined
1578 * by the component's registration
1580 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1582 INSTALLSTATE res;
1584 if (!comp->ComponentId)
1585 continue;
1587 res = MsiGetComponentPathW( package->ProductCode,
1588 comp->ComponentId, NULL, NULL);
1589 if (res < 0)
1590 res = INSTALLSTATE_ABSENT;
1591 comp->Installed = res;
1594 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1596 ComponentList *cl;
1597 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1599 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1601 comp= cl->component;
1603 if (!comp->ComponentId)
1605 res = INSTALLSTATE_ABSENT;
1606 break;
1609 if (res == INSTALLSTATE_ABSENT)
1610 res = comp->Installed;
1611 else
1613 if (res == comp->Installed)
1614 continue;
1616 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1617 res != INSTALLSTATE_SOURCE)
1619 res = INSTALLSTATE_INCOMPLETE;
1623 feature->Installed = res;
1627 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1628 INSTALLSTATE state)
1630 static const WCHAR all[]={'A','L','L',0};
1631 LPWSTR override;
1632 MSIFEATURE *feature;
1634 override = msi_dup_property( package, property );
1635 if (!override)
1636 return FALSE;
1638 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1640 if (strcmpiW(override,all)==0)
1642 feature->ActionRequest= state;
1643 feature->Action = state;
1645 else
1647 LPWSTR ptr = override;
1648 LPWSTR ptr2 = strchrW(override,',');
1650 while (ptr)
1652 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1653 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1655 feature->ActionRequest= state;
1656 feature->Action = state;
1657 break;
1659 if (ptr2)
1661 ptr=ptr2+1;
1662 ptr2 = strchrW(ptr,',');
1664 else
1665 break;
1669 msi_free(override);
1671 return TRUE;
1674 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1676 int install_level;
1677 static const WCHAR szlevel[] =
1678 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1679 static const WCHAR szAddLocal[] =
1680 {'A','D','D','L','O','C','A','L',0};
1681 static const WCHAR szRemove[] =
1682 {'R','E','M','O','V','E',0};
1683 static const WCHAR szReinstall[] =
1684 {'R','E','I','N','S','T','A','L','L',0};
1685 BOOL override = FALSE;
1686 MSICOMPONENT* component;
1687 MSIFEATURE *feature;
1690 /* I do not know if this is where it should happen.. but */
1692 TRACE("Checking Install Level\n");
1694 install_level = msi_get_property_int( package, szlevel, 1 );
1696 /* ok hereis the _real_ rub
1697 * all these activation/deactivation things happen in order and things
1698 * later on the list override things earlier on the list.
1699 * 1) INSTALLLEVEL processing
1700 * 2) ADDLOCAL
1701 * 3) REMOVE
1702 * 4) ADDSOURCE
1703 * 5) ADDDEFAULT
1704 * 6) REINSTALL
1705 * 7) COMPADDLOCAL
1706 * 8) COMPADDSOURCE
1707 * 9) FILEADDLOCAL
1708 * 10) FILEADDSOURCE
1709 * 11) FILEADDDEFAULT
1710 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1711 * ignored for all the features. seems strange, especially since it is not
1712 * documented anywhere, but it is how it works.
1714 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1715 * REMOVE are the big ones, since we don't handle administrative installs
1716 * yet anyway.
1718 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1719 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1720 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1722 if (!override)
1724 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1726 BOOL feature_state = ((feature->Level > 0) &&
1727 (feature->Level <= install_level));
1729 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1731 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1733 feature->ActionRequest = INSTALLSTATE_SOURCE;
1734 feature->Action = INSTALLSTATE_SOURCE;
1736 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1738 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1739 feature->Action = INSTALLSTATE_ADVERTISED;
1741 else
1743 feature->ActionRequest = INSTALLSTATE_LOCAL;
1744 feature->Action = INSTALLSTATE_LOCAL;
1749 /* disable child features of unselected parent features */
1750 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1752 FeatureList *fl;
1754 if (feature->Level > 0 && feature->Level <= install_level)
1755 continue;
1757 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1759 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1760 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1764 else
1766 /* set the Preselected Property */
1767 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1768 static const WCHAR szOne[] = { '1', 0 };
1770 MSI_SetPropertyW(package,szPreselected,szOne);
1774 * now we want to enable or disable components base on feature
1777 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1779 ComponentList *cl;
1781 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1782 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1783 feature->ActionRequest);
1785 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1787 component = cl->component;
1789 if (!component->Enabled)
1791 component->Action = INSTALLSTATE_UNKNOWN;
1792 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1794 else
1796 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1798 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1800 component->Action = INSTALLSTATE_LOCAL;
1801 component->ActionRequest = INSTALLSTATE_LOCAL;
1804 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1806 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1807 (component->Action == INSTALLSTATE_ABSENT) ||
1808 (component->Action == INSTALLSTATE_ADVERTISED) ||
1809 (component->Action == INSTALLSTATE_DEFAULT))
1812 component->Action = INSTALLSTATE_SOURCE;
1813 component->ActionRequest = INSTALLSTATE_SOURCE;
1816 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1818 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1819 (component->Action == INSTALLSTATE_ABSENT))
1822 component->Action = INSTALLSTATE_ADVERTISED;
1823 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1826 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1828 if (component->Action == INSTALLSTATE_UNKNOWN)
1830 component->Action = INSTALLSTATE_ABSENT;
1831 component->ActionRequest = INSTALLSTATE_ABSENT;
1834 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1836 component->Action = INSTALLSTATE_UNKNOWN;
1837 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1841 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1843 feature->Action = INSTALLSTATE_LOCAL;
1844 feature->ActionRequest = INSTALLSTATE_LOCAL;
1849 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1851 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1852 debugstr_w(component->Component), component->Installed,
1853 component->Action, component->ActionRequest);
1857 return ERROR_SUCCESS;
1860 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1862 MSIPACKAGE *package = (MSIPACKAGE*)param;
1863 LPCWSTR name;
1864 LPWSTR path;
1866 name = MSI_RecordGetString(row,1);
1868 /* This helper function now does ALL the work */
1869 TRACE("Dir %s ...\n",debugstr_w(name));
1870 load_folder(package,name);
1871 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1872 TRACE("resolves to %s\n",debugstr_w(path));
1873 msi_free(path);
1875 return ERROR_SUCCESS;
1878 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1880 MSIPACKAGE *package = (MSIPACKAGE*)param;
1881 LPCWSTR name;
1882 MSIFEATURE *feature;
1884 name = MSI_RecordGetString( row, 1 );
1886 feature = get_loaded_feature( package, name );
1887 if (!feature)
1888 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1889 else
1891 LPCWSTR Condition;
1892 Condition = MSI_RecordGetString(row,3);
1894 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1896 int level = MSI_RecordGetInteger(row,2);
1897 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1898 feature->Level = level;
1901 return ERROR_SUCCESS;
1904 static void load_all_component_states(MSIPACKAGE *package)
1906 MSICOMPONENT *comp;
1908 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1910 switch (comp->Attributes)
1912 case msidbComponentAttributesLocalOnly:
1913 comp->Action = INSTALLSTATE_LOCAL;
1914 comp->ActionRequest = INSTALLSTATE_LOCAL;
1915 break;
1916 case msidbComponentAttributesSourceOnly:
1917 comp->Action = INSTALLSTATE_SOURCE;
1918 comp->ActionRequest = INSTALLSTATE_SOURCE;
1919 break;
1920 case msidbComponentAttributesOptional:
1921 comp->Action = INSTALLSTATE_DEFAULT;
1922 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1923 break;
1924 default:
1925 comp->Action = INSTALLSTATE_LOCAL;
1926 comp->ActionRequest = INSTALLSTATE_LOCAL;
1932 * A lot is done in this function aside from just the costing.
1933 * The costing needs to be implemented at some point but for now I am going
1934 * to focus on the directory building
1937 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1939 static const WCHAR ExecSeqQuery[] =
1940 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1941 '`','D','i','r','e','c','t','o','r','y','`',0};
1942 static const WCHAR ConditionQuery[] =
1943 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1944 '`','C','o','n','d','i','t','i','o','n','`',0};
1945 static const WCHAR szCosting[] =
1946 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1947 static const WCHAR szlevel[] =
1948 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1949 static const WCHAR szOne[] = { '1', 0 };
1950 MSICOMPONENT *comp;
1951 MSIFILE *file;
1952 UINT rc;
1953 MSIQUERY * view;
1954 LPWSTR level;
1956 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1957 return ERROR_SUCCESS;
1959 TRACE("Building Directory properties\n");
1961 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1962 if (rc == ERROR_SUCCESS)
1964 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1965 package);
1966 msiobj_release(&view->hdr);
1969 load_all_component_states(package);
1971 TRACE("File calculations\n");
1973 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1975 MSICOMPONENT* comp = file->Component;
1976 LPWSTR p;
1978 if (!comp)
1979 continue;
1981 if (file->IsCompressed)
1983 comp->ForceLocalState = TRUE;
1984 comp->Action = INSTALLSTATE_LOCAL;
1985 comp->ActionRequest = INSTALLSTATE_LOCAL;
1988 /* calculate target */
1989 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1991 msi_free(file->TargetPath);
1993 TRACE("file %s is named %s\n",
1994 debugstr_w(file->File),debugstr_w(file->FileName));
1996 file->TargetPath = build_directory_name(2, p, file->FileName);
1998 msi_free(p);
2000 TRACE("file %s resolves to %s\n",
2001 debugstr_w(file->File),debugstr_w(file->TargetPath));
2003 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2005 file->state = msifs_missing;
2006 comp->Cost += file->FileSize;
2007 continue;
2010 if (file->Version)
2012 DWORD handle;
2013 DWORD versize;
2014 UINT sz;
2015 LPVOID version;
2016 static WCHAR name[] = {'\\',0};
2017 static const WCHAR name_fmt[] =
2018 {'%','u','.','%','u','.','%','u','.','%','u',0};
2019 WCHAR filever[0x100];
2020 VS_FIXEDFILEINFO *lpVer;
2022 TRACE("Version comparison..\n");
2023 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2024 version = msi_alloc(versize);
2025 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2027 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2029 sprintfW(filever,name_fmt,
2030 HIWORD(lpVer->dwFileVersionMS),
2031 LOWORD(lpVer->dwFileVersionMS),
2032 HIWORD(lpVer->dwFileVersionLS),
2033 LOWORD(lpVer->dwFileVersionLS));
2035 TRACE("new %s old %s\n", debugstr_w(file->Version),
2036 debugstr_w(filever));
2037 if (strcmpiW(filever,file->Version)<0)
2039 file->state = msifs_overwrite;
2040 /* FIXME: cost should be diff in size */
2041 comp->Cost += file->FileSize;
2043 else
2044 file->state = msifs_present;
2045 msi_free(version);
2047 else
2048 file->state = msifs_present;
2051 TRACE("Evaluating Condition Table\n");
2053 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2054 if (rc == ERROR_SUCCESS)
2056 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2057 package);
2058 msiobj_release(&view->hdr);
2061 TRACE("Enabling or Disabling Components\n");
2062 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2064 if (comp->Condition)
2066 if (MSI_EvaluateConditionW(package,
2067 comp->Condition) == MSICONDITION_FALSE)
2069 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2070 comp->Enabled = FALSE;
2075 MSI_SetPropertyW(package,szCosting,szOne);
2076 /* set default run level if not set */
2077 level = msi_dup_property( package, szlevel );
2078 if (!level)
2079 MSI_SetPropertyW(package,szlevel, szOne);
2080 msi_free(level);
2082 ACTION_UpdateInstallStates(package);
2084 return MSI_SetFeatureStates(package);
2087 /* OK this value is "interpreted" and then formatted based on the
2088 first few characters */
2089 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2090 DWORD *size)
2092 LPSTR data = NULL;
2093 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2095 if (value[1]=='x')
2097 LPWSTR ptr;
2098 CHAR byte[5];
2099 LPWSTR deformated = NULL;
2100 int count;
2102 deformat_string(package, &value[2], &deformated);
2104 /* binary value type */
2105 ptr = deformated;
2106 *type = REG_BINARY;
2107 if (strlenW(ptr)%2)
2108 *size = (strlenW(ptr)/2)+1;
2109 else
2110 *size = strlenW(ptr)/2;
2112 data = msi_alloc(*size);
2114 byte[0] = '0';
2115 byte[1] = 'x';
2116 byte[4] = 0;
2117 count = 0;
2118 /* if uneven pad with a zero in front */
2119 if (strlenW(ptr)%2)
2121 byte[2]= '0';
2122 byte[3]= *ptr;
2123 ptr++;
2124 data[count] = (BYTE)strtol(byte,NULL,0);
2125 count ++;
2126 TRACE("Uneven byte count\n");
2128 while (*ptr)
2130 byte[2]= *ptr;
2131 ptr++;
2132 byte[3]= *ptr;
2133 ptr++;
2134 data[count] = (BYTE)strtol(byte,NULL,0);
2135 count ++;
2137 msi_free(deformated);
2139 TRACE("Data %i bytes(%i)\n",*size,count);
2141 else
2143 LPWSTR deformated;
2144 LPWSTR p;
2145 DWORD d = 0;
2146 deformat_string(package, &value[1], &deformated);
2148 *type=REG_DWORD;
2149 *size = sizeof(DWORD);
2150 data = msi_alloc(*size);
2151 p = deformated;
2152 if (*p == '-')
2153 p++;
2154 while (*p)
2156 if ( (*p < '0') || (*p > '9') )
2157 break;
2158 d *= 10;
2159 d += (*p - '0');
2160 p++;
2162 if (deformated[0] == '-')
2163 d = -d;
2164 *(LPDWORD)data = d;
2165 TRACE("DWORD %i\n",*(LPDWORD)data);
2167 msi_free(deformated);
2170 else
2172 static const WCHAR szMulti[] = {'[','~',']',0};
2173 LPCWSTR ptr;
2174 *type=REG_SZ;
2176 if (value[0]=='#')
2178 if (value[1]=='%')
2180 ptr = &value[2];
2181 *type=REG_EXPAND_SZ;
2183 else
2184 ptr = &value[1];
2186 else
2187 ptr=value;
2189 if (strstrW(value,szMulti))
2190 *type = REG_MULTI_SZ;
2192 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2194 return data;
2197 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2199 MSIPACKAGE *package = (MSIPACKAGE*)param;
2200 static const WCHAR szHCR[] =
2201 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2202 'R','O','O','T','\\',0};
2203 static const WCHAR szHCU[] =
2204 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2205 'U','S','E','R','\\',0};
2206 static const WCHAR szHLM[] =
2207 {'H','K','E','Y','_','L','O','C','A','L','_',
2208 'M','A','C','H','I','N','E','\\',0};
2209 static const WCHAR szHU[] =
2210 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2212 LPSTR value_data = NULL;
2213 HKEY root_key, hkey;
2214 DWORD type,size;
2215 LPWSTR deformated;
2216 LPCWSTR szRoot, component, name, key, value;
2217 MSICOMPONENT *comp;
2218 MSIRECORD * uirow;
2219 LPWSTR uikey;
2220 INT root;
2221 BOOL check_first = FALSE;
2222 UINT rc;
2224 ui_progress(package,2,0,0,0);
2226 value = NULL;
2227 key = NULL;
2228 uikey = NULL;
2229 name = NULL;
2231 component = MSI_RecordGetString(row, 6);
2232 comp = get_loaded_component(package,component);
2233 if (!comp)
2234 return ERROR_SUCCESS;
2236 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2238 TRACE("Skipping write due to disabled component %s\n",
2239 debugstr_w(component));
2241 comp->Action = comp->Installed;
2243 return ERROR_SUCCESS;
2246 comp->Action = INSTALLSTATE_LOCAL;
2248 name = MSI_RecordGetString(row, 4);
2249 if( MSI_RecordIsNull(row,5) && name )
2251 /* null values can have special meanings */
2252 if (name[0]=='-' && name[1] == 0)
2253 return ERROR_SUCCESS;
2254 else if ((name[0]=='+' && name[1] == 0) ||
2255 (name[0] == '*' && name[1] == 0))
2256 name = NULL;
2257 check_first = TRUE;
2260 root = MSI_RecordGetInteger(row,2);
2261 key = MSI_RecordGetString(row, 3);
2263 /* get the root key */
2264 switch (root)
2266 case -1:
2268 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2269 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2270 if (all_users && all_users[0] == '1')
2272 root_key = HKEY_LOCAL_MACHINE;
2273 szRoot = szHLM;
2275 else
2277 root_key = HKEY_CURRENT_USER;
2278 szRoot = szHCU;
2280 msi_free(all_users);
2282 break;
2283 case 0: root_key = HKEY_CLASSES_ROOT;
2284 szRoot = szHCR;
2285 break;
2286 case 1: root_key = HKEY_CURRENT_USER;
2287 szRoot = szHCU;
2288 break;
2289 case 2: root_key = HKEY_LOCAL_MACHINE;
2290 szRoot = szHLM;
2291 break;
2292 case 3: root_key = HKEY_USERS;
2293 szRoot = szHU;
2294 break;
2295 default:
2296 ERR("Unknown root %i\n",root);
2297 root_key=NULL;
2298 szRoot = NULL;
2299 break;
2301 if (!root_key)
2302 return ERROR_SUCCESS;
2304 deformat_string(package, key , &deformated);
2305 size = strlenW(deformated) + strlenW(szRoot) + 1;
2306 uikey = msi_alloc(size*sizeof(WCHAR));
2307 strcpyW(uikey,szRoot);
2308 strcatW(uikey,deformated);
2310 if (RegCreateKeyW( root_key, deformated, &hkey))
2312 ERR("Could not create key %s\n",debugstr_w(deformated));
2313 msi_free(deformated);
2314 msi_free(uikey);
2315 return ERROR_SUCCESS;
2317 msi_free(deformated);
2319 value = MSI_RecordGetString(row,5);
2320 if (value)
2321 value_data = parse_value(package, value, &type, &size);
2322 else
2324 static const WCHAR szEmpty[] = {0};
2325 value_data = (LPSTR)strdupW(szEmpty);
2326 size = 0;
2327 type = REG_SZ;
2330 deformat_string(package, name, &deformated);
2332 /* get the double nulls to terminate SZ_MULTI */
2333 if (type == REG_MULTI_SZ)
2334 size +=sizeof(WCHAR);
2336 if (!check_first)
2338 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2339 debugstr_w(uikey));
2340 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2342 else
2344 DWORD sz = 0;
2345 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2346 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2348 TRACE("value %s of %s checked already exists\n",
2349 debugstr_w(deformated), debugstr_w(uikey));
2351 else
2353 TRACE("Checked and setting value %s of %s\n",
2354 debugstr_w(deformated), debugstr_w(uikey));
2355 if (deformated || size)
2356 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2359 RegCloseKey(hkey);
2361 uirow = MSI_CreateRecord(3);
2362 MSI_RecordSetStringW(uirow,2,deformated);
2363 MSI_RecordSetStringW(uirow,1,uikey);
2365 if (type == REG_SZ)
2366 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2367 else
2368 MSI_RecordSetStringW(uirow,3,value);
2370 ui_actiondata(package,szWriteRegistryValues,uirow);
2371 msiobj_release( &uirow->hdr );
2373 msi_free(value_data);
2374 msi_free(deformated);
2375 msi_free(uikey);
2377 return ERROR_SUCCESS;
2380 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2382 UINT rc;
2383 MSIQUERY * view;
2384 static const WCHAR ExecSeqQuery[] =
2385 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2386 '`','R','e','g','i','s','t','r','y','`',0 };
2388 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2389 if (rc != ERROR_SUCCESS)
2390 return ERROR_SUCCESS;
2392 /* increment progress bar each time action data is sent */
2393 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2395 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2397 msiobj_release(&view->hdr);
2398 return rc;
2401 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2403 package->script->CurrentlyScripting = TRUE;
2405 return ERROR_SUCCESS;
2409 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2411 MSICOMPONENT *comp;
2412 DWORD progress = 0;
2413 DWORD total = 0;
2414 static const WCHAR q1[]=
2415 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2416 '`','R','e','g','i','s','t','r','y','`',0};
2417 UINT rc;
2418 MSIQUERY * view;
2419 MSIFEATURE *feature;
2420 MSIFILE *file;
2422 TRACE("InstallValidate\n");
2424 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2425 if (rc == ERROR_SUCCESS)
2427 MSI_IterateRecords( view, &progress, NULL, package );
2428 msiobj_release( &view->hdr );
2429 total += progress * REG_PROGRESS_VALUE;
2432 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2433 total += COMPONENT_PROGRESS_VALUE;
2435 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2436 total += file->FileSize;
2438 ui_progress(package,0,total,0,0);
2440 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2442 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2443 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2444 feature->ActionRequest);
2447 return ERROR_SUCCESS;
2450 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2452 MSIPACKAGE* package = (MSIPACKAGE*)param;
2453 LPCWSTR cond = NULL;
2454 LPCWSTR message = NULL;
2455 static const WCHAR title[]=
2456 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2458 cond = MSI_RecordGetString(row,1);
2460 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2462 LPWSTR deformated;
2463 message = MSI_RecordGetString(row,2);
2464 deformat_string(package,message,&deformated);
2465 MessageBoxW(NULL,deformated,title,MB_OK);
2466 msi_free(deformated);
2467 return ERROR_FUNCTION_FAILED;
2470 return ERROR_SUCCESS;
2473 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2475 UINT rc;
2476 MSIQUERY * view = NULL;
2477 static const WCHAR ExecSeqQuery[] =
2478 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2479 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2481 TRACE("Checking launch conditions\n");
2483 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2484 if (rc != ERROR_SUCCESS)
2485 return ERROR_SUCCESS;
2487 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2488 msiobj_release(&view->hdr);
2490 return rc;
2493 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2496 if (!cmp->KeyPath)
2497 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2499 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2501 MSIRECORD * row = 0;
2502 UINT root,len;
2503 LPWSTR deformated,buffer,deformated_name;
2504 LPCWSTR key,name;
2505 static const WCHAR ExecSeqQuery[] =
2506 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2507 '`','R','e','g','i','s','t','r','y','`',' ',
2508 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2509 ' ','=',' ' ,'\'','%','s','\'',0 };
2510 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2511 static const WCHAR fmt2[]=
2512 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2514 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2515 if (!row)
2516 return NULL;
2518 root = MSI_RecordGetInteger(row,2);
2519 key = MSI_RecordGetString(row, 3);
2520 name = MSI_RecordGetString(row, 4);
2521 deformat_string(package, key , &deformated);
2522 deformat_string(package, name, &deformated_name);
2524 len = strlenW(deformated) + 6;
2525 if (deformated_name)
2526 len+=strlenW(deformated_name);
2528 buffer = msi_alloc( len *sizeof(WCHAR));
2530 if (deformated_name)
2531 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2532 else
2533 sprintfW(buffer,fmt,root,deformated);
2535 msi_free(deformated);
2536 msi_free(deformated_name);
2537 msiobj_release(&row->hdr);
2539 return buffer;
2541 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2543 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2544 return NULL;
2546 else
2548 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2550 if (file)
2551 return strdupW( file->TargetPath );
2553 return NULL;
2556 static HKEY openSharedDLLsKey(void)
2558 HKEY hkey=0;
2559 static const WCHAR path[] =
2560 {'S','o','f','t','w','a','r','e','\\',
2561 'M','i','c','r','o','s','o','f','t','\\',
2562 'W','i','n','d','o','w','s','\\',
2563 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2564 'S','h','a','r','e','d','D','L','L','s',0};
2566 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2567 return hkey;
2570 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2572 HKEY hkey;
2573 DWORD count=0;
2574 DWORD type;
2575 DWORD sz = sizeof(count);
2576 DWORD rc;
2578 hkey = openSharedDLLsKey();
2579 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2580 if (rc != ERROR_SUCCESS)
2581 count = 0;
2582 RegCloseKey(hkey);
2583 return count;
2586 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2588 HKEY hkey;
2590 hkey = openSharedDLLsKey();
2591 if (count > 0)
2592 msi_reg_set_val_dword( hkey, path, count );
2593 else
2594 RegDeleteValueW(hkey,path);
2595 RegCloseKey(hkey);
2596 return count;
2600 * Return TRUE if the count should be written out and FALSE if not
2602 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2604 MSIFEATURE *feature;
2605 INT count = 0;
2606 BOOL write = FALSE;
2608 /* only refcount DLLs */
2609 if (comp->KeyPath == NULL ||
2610 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2611 comp->Attributes & msidbComponentAttributesODBCDataSource)
2612 write = FALSE;
2613 else
2615 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2616 write = (count > 0);
2618 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2619 write = TRUE;
2622 /* increment counts */
2623 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2625 ComponentList *cl;
2627 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2628 continue;
2630 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2632 if ( cl->component == comp )
2633 count++;
2637 /* decrement counts */
2638 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2640 ComponentList *cl;
2642 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2643 continue;
2645 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2647 if ( cl->component == comp )
2648 count--;
2652 /* ref count all the files in the component */
2653 if (write)
2655 MSIFILE *file;
2657 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2659 if (file->Component == comp)
2660 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2664 /* add a count for permenent */
2665 if (comp->Attributes & msidbComponentAttributesPermanent)
2666 count ++;
2668 comp->RefCount = count;
2670 if (write)
2671 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2675 * Ok further analysis makes me think that this work is
2676 * actually done in the PublishComponents and PublishFeatures
2677 * step, and not here. It appears like the keypath and all that is
2678 * resolved in this step, however actually written in the Publish steps.
2679 * But we will leave it here for now because it is unclear
2681 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2683 WCHAR squished_pc[GUID_SIZE];
2684 WCHAR squished_cc[GUID_SIZE];
2685 UINT rc;
2686 MSICOMPONENT *comp;
2687 HKEY hkey=0,hkey2=0;
2689 /* writes the Component and Features values to the registry */
2691 rc = MSIREG_OpenComponents(&hkey);
2692 if (rc != ERROR_SUCCESS)
2693 return rc;
2695 squash_guid(package->ProductCode,squished_pc);
2696 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2698 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2700 MSIRECORD * uirow;
2702 ui_progress(package,2,0,0,0);
2703 if (!comp->ComponentId)
2704 continue;
2706 squash_guid(comp->ComponentId,squished_cc);
2708 msi_free(comp->FullKeypath);
2709 comp->FullKeypath = resolve_keypath( package, comp );
2711 /* do the refcounting */
2712 ACTION_RefCountComponent( package, comp );
2714 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2715 debugstr_w(comp->Component),
2716 debugstr_w(squished_cc),
2717 debugstr_w(comp->FullKeypath),
2718 comp->RefCount);
2720 * Write the keypath out if the component is to be registered
2721 * and delete the key if the component is to be deregistered
2723 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2725 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2726 if (rc != ERROR_SUCCESS)
2727 continue;
2729 if (!comp->FullKeypath)
2730 continue;
2732 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2734 if (comp->Attributes & msidbComponentAttributesPermanent)
2736 static const WCHAR szPermKey[] =
2737 { '0','0','0','0','0','0','0','0','0','0','0','0',
2738 '0','0','0','0','0','0','0','0','0','0','0','0',
2739 '0','0','0','0','0','0','0','0',0 };
2741 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2744 RegCloseKey(hkey2);
2746 /* UI stuff */
2747 uirow = MSI_CreateRecord(3);
2748 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2749 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2750 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2751 ui_actiondata(package,szProcessComponents,uirow);
2752 msiobj_release( &uirow->hdr );
2754 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2756 DWORD res;
2758 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2759 if (rc != ERROR_SUCCESS)
2760 continue;
2762 RegDeleteValueW(hkey2,squished_pc);
2764 /* if the key is empty delete it */
2765 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2766 RegCloseKey(hkey2);
2767 if (res == ERROR_NO_MORE_ITEMS)
2768 RegDeleteKeyW(hkey,squished_cc);
2770 /* UI stuff */
2771 uirow = MSI_CreateRecord(2);
2772 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2773 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2774 ui_actiondata(package,szProcessComponents,uirow);
2775 msiobj_release( &uirow->hdr );
2778 RegCloseKey(hkey);
2779 return rc;
2782 typedef struct {
2783 CLSID clsid;
2784 LPWSTR source;
2786 LPWSTR path;
2787 ITypeLib *ptLib;
2788 } typelib_struct;
2790 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2791 LPWSTR lpszName, LONG_PTR lParam)
2793 TLIBATTR *attr;
2794 typelib_struct *tl_struct = (typelib_struct*) lParam;
2795 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2796 int sz;
2797 HRESULT res;
2799 if (!IS_INTRESOURCE(lpszName))
2801 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2802 return TRUE;
2805 sz = strlenW(tl_struct->source)+4;
2806 sz *= sizeof(WCHAR);
2808 if ((INT_PTR)lpszName == 1)
2809 tl_struct->path = strdupW(tl_struct->source);
2810 else
2812 tl_struct->path = msi_alloc(sz);
2813 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2816 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2817 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2818 if (!SUCCEEDED(res))
2820 msi_free(tl_struct->path);
2821 tl_struct->path = NULL;
2823 return TRUE;
2826 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2827 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2829 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2830 return FALSE;
2833 msi_free(tl_struct->path);
2834 tl_struct->path = NULL;
2836 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2837 ITypeLib_Release(tl_struct->ptLib);
2839 return TRUE;
2842 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2844 MSIPACKAGE* package = (MSIPACKAGE*)param;
2845 LPCWSTR component;
2846 MSICOMPONENT *comp;
2847 MSIFILE *file;
2848 typelib_struct tl_struct;
2849 HMODULE module;
2850 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2852 component = MSI_RecordGetString(row,3);
2853 comp = get_loaded_component(package,component);
2854 if (!comp)
2855 return ERROR_SUCCESS;
2857 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2859 TRACE("Skipping typelib reg due to disabled component\n");
2861 comp->Action = comp->Installed;
2863 return ERROR_SUCCESS;
2866 comp->Action = INSTALLSTATE_LOCAL;
2868 file = get_loaded_file( package, comp->KeyPath );
2869 if (!file)
2870 return ERROR_SUCCESS;
2872 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2873 if (module)
2875 LPCWSTR guid;
2876 guid = MSI_RecordGetString(row,1);
2877 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2878 tl_struct.source = strdupW( file->TargetPath );
2879 tl_struct.path = NULL;
2881 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2882 (LONG_PTR)&tl_struct);
2884 if (tl_struct.path)
2886 LPWSTR help = NULL;
2887 LPCWSTR helpid;
2888 HRESULT res;
2890 helpid = MSI_RecordGetString(row,6);
2892 if (helpid)
2893 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2894 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2895 msi_free(help);
2897 if (!SUCCEEDED(res))
2898 ERR("Failed to register type library %s\n",
2899 debugstr_w(tl_struct.path));
2900 else
2902 ui_actiondata(package,szRegisterTypeLibraries,row);
2904 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2907 ITypeLib_Release(tl_struct.ptLib);
2908 msi_free(tl_struct.path);
2910 else
2911 ERR("Failed to load type library %s\n",
2912 debugstr_w(tl_struct.source));
2914 FreeLibrary(module);
2915 msi_free(tl_struct.source);
2917 else
2918 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2920 return ERROR_SUCCESS;
2923 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2926 * OK this is a bit confusing.. I am given a _Component key and I believe
2927 * that the file that is being registered as a type library is the "key file
2928 * of that component" which I interpret to mean "The file in the KeyPath of
2929 * that component".
2931 UINT rc;
2932 MSIQUERY * view;
2933 static const WCHAR Query[] =
2934 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2935 '`','T','y','p','e','L','i','b','`',0};
2937 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2938 if (rc != ERROR_SUCCESS)
2939 return ERROR_SUCCESS;
2941 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2942 msiobj_release(&view->hdr);
2943 return rc;
2946 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2948 MSIPACKAGE *package = (MSIPACKAGE*)param;
2949 LPWSTR target_file, target_folder, filename;
2950 LPCWSTR buffer, extension;
2951 MSICOMPONENT *comp;
2952 static const WCHAR szlnk[]={'.','l','n','k',0};
2953 IShellLinkW *sl = NULL;
2954 IPersistFile *pf = NULL;
2955 HRESULT res;
2957 buffer = MSI_RecordGetString(row,4);
2958 comp = get_loaded_component(package,buffer);
2959 if (!comp)
2960 return ERROR_SUCCESS;
2962 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2964 TRACE("Skipping shortcut creation due to disabled component\n");
2966 comp->Action = comp->Installed;
2968 return ERROR_SUCCESS;
2971 comp->Action = INSTALLSTATE_LOCAL;
2973 ui_actiondata(package,szCreateShortcuts,row);
2975 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2976 &IID_IShellLinkW, (LPVOID *) &sl );
2978 if (FAILED( res ))
2980 ERR("CLSID_ShellLink not available\n");
2981 goto err;
2984 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2985 if (FAILED( res ))
2987 ERR("QueryInterface(IID_IPersistFile) failed\n");
2988 goto err;
2991 buffer = MSI_RecordGetString(row,2);
2992 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2994 /* may be needed because of a bug somehwere else */
2995 create_full_pathW(target_folder);
2997 filename = msi_dup_record_field( row, 3 );
2998 reduce_to_longfilename(filename);
3000 extension = strchrW(filename,'.');
3001 if (!extension || strcmpiW(extension,szlnk))
3003 int len = strlenW(filename);
3004 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3005 memcpy(filename + len, szlnk, sizeof(szlnk));
3007 target_file = build_directory_name(2, target_folder, filename);
3008 msi_free(target_folder);
3009 msi_free(filename);
3011 buffer = MSI_RecordGetString(row,5);
3012 if (strchrW(buffer,'['))
3014 LPWSTR deformated;
3015 deformat_string(package,buffer,&deformated);
3016 IShellLinkW_SetPath(sl,deformated);
3017 msi_free(deformated);
3019 else
3021 FIXME("poorly handled shortcut format, advertised shortcut\n");
3022 IShellLinkW_SetPath(sl,comp->FullKeypath);
3025 if (!MSI_RecordIsNull(row,6))
3027 LPWSTR deformated;
3028 buffer = MSI_RecordGetString(row,6);
3029 deformat_string(package,buffer,&deformated);
3030 IShellLinkW_SetArguments(sl,deformated);
3031 msi_free(deformated);
3034 if (!MSI_RecordIsNull(row,7))
3036 buffer = MSI_RecordGetString(row,7);
3037 IShellLinkW_SetDescription(sl,buffer);
3040 if (!MSI_RecordIsNull(row,8))
3041 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3043 if (!MSI_RecordIsNull(row,9))
3045 LPWSTR Path;
3046 INT index;
3048 buffer = MSI_RecordGetString(row,9);
3050 Path = build_icon_path(package,buffer);
3051 index = MSI_RecordGetInteger(row,10);
3053 /* no value means 0 */
3054 if (index == MSI_NULL_INTEGER)
3055 index = 0;
3057 IShellLinkW_SetIconLocation(sl,Path,index);
3058 msi_free(Path);
3061 if (!MSI_RecordIsNull(row,11))
3062 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3064 if (!MSI_RecordIsNull(row,12))
3066 LPWSTR Path;
3067 buffer = MSI_RecordGetString(row,12);
3068 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3069 if (Path)
3070 IShellLinkW_SetWorkingDirectory(sl,Path);
3071 msi_free(Path);
3074 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3075 IPersistFile_Save(pf,target_file,FALSE);
3077 msi_free(target_file);
3079 err:
3080 if (pf)
3081 IPersistFile_Release( pf );
3082 if (sl)
3083 IShellLinkW_Release( sl );
3085 return ERROR_SUCCESS;
3088 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3090 UINT rc;
3091 HRESULT res;
3092 MSIQUERY * view;
3093 static const WCHAR Query[] =
3094 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3095 '`','S','h','o','r','t','c','u','t','`',0};
3097 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3098 if (rc != ERROR_SUCCESS)
3099 return ERROR_SUCCESS;
3101 res = CoInitialize( NULL );
3102 if (FAILED (res))
3104 ERR("CoInitialize failed\n");
3105 return ERROR_FUNCTION_FAILED;
3108 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3109 msiobj_release(&view->hdr);
3111 CoUninitialize();
3113 return rc;
3116 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3118 MSIPACKAGE* package = (MSIPACKAGE*)param;
3119 HANDLE the_file;
3120 LPWSTR FilePath;
3121 LPCWSTR FileName;
3122 CHAR buffer[1024];
3123 DWORD sz;
3124 UINT rc;
3125 MSIRECORD *uirow;
3127 FileName = MSI_RecordGetString(row,1);
3128 if (!FileName)
3130 ERR("Unable to get FileName\n");
3131 return ERROR_SUCCESS;
3134 FilePath = build_icon_path(package,FileName);
3136 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3138 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3139 FILE_ATTRIBUTE_NORMAL, NULL);
3141 if (the_file == INVALID_HANDLE_VALUE)
3143 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3144 msi_free(FilePath);
3145 return ERROR_SUCCESS;
3150 DWORD write;
3151 sz = 1024;
3152 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3153 if (rc != ERROR_SUCCESS)
3155 ERR("Failed to get stream\n");
3156 CloseHandle(the_file);
3157 DeleteFileW(FilePath);
3158 break;
3160 WriteFile(the_file,buffer,sz,&write,NULL);
3161 } while (sz == 1024);
3163 msi_free(FilePath);
3165 CloseHandle(the_file);
3167 uirow = MSI_CreateRecord(1);
3168 MSI_RecordSetStringW(uirow,1,FileName);
3169 ui_actiondata(package,szPublishProduct,uirow);
3170 msiobj_release( &uirow->hdr );
3172 return ERROR_SUCCESS;
3176 * 99% of the work done here is only done for
3177 * advertised installs. However this is where the
3178 * Icon table is processed and written out
3179 * so that is what I am going to do here.
3181 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3183 UINT rc;
3184 MSIQUERY * view;
3185 static const WCHAR Query[]=
3186 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3187 '`','I','c','o','n','`',0};
3188 /* for registry stuff */
3189 HKEY hkey=0;
3190 HKEY hukey=0;
3191 static const WCHAR szProductLanguage[] =
3192 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3193 static const WCHAR szARPProductIcon[] =
3194 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3195 static const WCHAR szProductVersion[] =
3196 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3197 DWORD langid;
3198 LPWSTR buffer;
3199 DWORD size;
3200 MSIHANDLE hDb, hSumInfo;
3202 /* write out icon files */
3204 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3205 if (rc == ERROR_SUCCESS)
3207 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3208 msiobj_release(&view->hdr);
3211 /* ok there is a lot more done here but i need to figure out what */
3213 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3214 if (rc != ERROR_SUCCESS)
3215 goto end;
3217 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3218 if (rc != ERROR_SUCCESS)
3219 goto end;
3222 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3223 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3224 msi_free(buffer);
3226 langid = msi_get_property_int( package, szProductLanguage, 0 );
3227 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3229 buffer = msi_dup_property( package, szARPProductIcon );
3230 if (buffer)
3232 LPWSTR path = build_icon_path(package,buffer);
3233 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3234 msi_free( path );
3236 msi_free(buffer);
3238 buffer = msi_dup_property( package, szProductVersion );
3239 if (buffer)
3241 DWORD verdword = msi_version_str_to_dword(buffer);
3242 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3244 msi_free(buffer);
3246 /* FIXME: Need to write more keys to the user registry */
3248 hDb= alloc_msihandle( &package->db->hdr );
3249 if (!hDb) {
3250 rc = ERROR_NOT_ENOUGH_MEMORY;
3251 goto end;
3253 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3254 MsiCloseHandle(hDb);
3255 if (rc == ERROR_SUCCESS)
3257 WCHAR guidbuffer[0x200];
3258 size = 0x200;
3259 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3260 guidbuffer, &size);
3261 if (rc == ERROR_SUCCESS)
3263 WCHAR squashed[GUID_SIZE];
3264 /* for now we only care about the first guid */
3265 LPWSTR ptr = strchrW(guidbuffer,';');
3266 if (ptr) *ptr = 0;
3267 squash_guid(guidbuffer,squashed);
3268 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3270 else
3272 ERR("Unable to query Revision_Number...\n");
3273 rc = ERROR_SUCCESS;
3275 MsiCloseHandle(hSumInfo);
3277 else
3279 ERR("Unable to open Summary Information\n");
3280 rc = ERROR_SUCCESS;
3283 end:
3285 RegCloseKey(hkey);
3286 RegCloseKey(hukey);
3288 return rc;
3291 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3293 MSIPACKAGE *package = (MSIPACKAGE*)param;
3294 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3295 LPWSTR deformated_section, deformated_key, deformated_value;
3296 LPWSTR folder, fullname = NULL;
3297 MSIRECORD * uirow;
3298 INT action;
3299 MSICOMPONENT *comp;
3300 static const WCHAR szWindowsFolder[] =
3301 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3303 component = MSI_RecordGetString(row, 8);
3304 comp = get_loaded_component(package,component);
3306 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3308 TRACE("Skipping ini file due to disabled component %s\n",
3309 debugstr_w(component));
3311 comp->Action = comp->Installed;
3313 return ERROR_SUCCESS;
3316 comp->Action = INSTALLSTATE_LOCAL;
3318 identifier = MSI_RecordGetString(row,1);
3319 filename = MSI_RecordGetString(row,2);
3320 dirproperty = MSI_RecordGetString(row,3);
3321 section = MSI_RecordGetString(row,4);
3322 key = MSI_RecordGetString(row,5);
3323 value = MSI_RecordGetString(row,6);
3324 action = MSI_RecordGetInteger(row,7);
3326 deformat_string(package,section,&deformated_section);
3327 deformat_string(package,key,&deformated_key);
3328 deformat_string(package,value,&deformated_value);
3330 if (dirproperty)
3332 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3333 if (!folder)
3334 folder = msi_dup_property( package, dirproperty );
3336 else
3337 folder = msi_dup_property( package, szWindowsFolder );
3339 if (!folder)
3341 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3342 goto cleanup;
3345 fullname = build_directory_name(2, folder, filename);
3347 if (action == 0)
3349 TRACE("Adding value %s to section %s in %s\n",
3350 debugstr_w(deformated_key), debugstr_w(deformated_section),
3351 debugstr_w(fullname));
3352 WritePrivateProfileStringW(deformated_section, deformated_key,
3353 deformated_value, fullname);
3355 else if (action == 1)
3357 WCHAR returned[10];
3358 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3359 returned, 10, fullname);
3360 if (returned[0] == 0)
3362 TRACE("Adding value %s to section %s in %s\n",
3363 debugstr_w(deformated_key), debugstr_w(deformated_section),
3364 debugstr_w(fullname));
3366 WritePrivateProfileStringW(deformated_section, deformated_key,
3367 deformated_value, fullname);
3370 else if (action == 3)
3371 FIXME("Append to existing section not yet implemented\n");
3373 uirow = MSI_CreateRecord(4);
3374 MSI_RecordSetStringW(uirow,1,identifier);
3375 MSI_RecordSetStringW(uirow,2,deformated_section);
3376 MSI_RecordSetStringW(uirow,3,deformated_key);
3377 MSI_RecordSetStringW(uirow,4,deformated_value);
3378 ui_actiondata(package,szWriteIniValues,uirow);
3379 msiobj_release( &uirow->hdr );
3380 cleanup:
3381 msi_free(fullname);
3382 msi_free(folder);
3383 msi_free(deformated_key);
3384 msi_free(deformated_value);
3385 msi_free(deformated_section);
3386 return ERROR_SUCCESS;
3389 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3391 UINT rc;
3392 MSIQUERY * view;
3393 static const WCHAR ExecSeqQuery[] =
3394 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3395 '`','I','n','i','F','i','l','e','`',0};
3397 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3398 if (rc != ERROR_SUCCESS)
3400 TRACE("no IniFile table\n");
3401 return ERROR_SUCCESS;
3404 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3405 msiobj_release(&view->hdr);
3406 return rc;
3409 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3411 MSIPACKAGE *package = (MSIPACKAGE*)param;
3412 LPCWSTR filename;
3413 LPWSTR FullName;
3414 MSIFILE *file;
3415 DWORD len;
3416 static const WCHAR ExeStr[] =
3417 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3418 static const WCHAR close[] = {'\"',0};
3419 STARTUPINFOW si;
3420 PROCESS_INFORMATION info;
3421 BOOL brc;
3422 MSIRECORD *uirow;
3423 LPWSTR uipath, p;
3425 memset(&si,0,sizeof(STARTUPINFOW));
3427 filename = MSI_RecordGetString(row,1);
3428 file = get_loaded_file( package, filename );
3430 if (!file)
3432 ERR("Unable to find file id %s\n",debugstr_w(filename));
3433 return ERROR_SUCCESS;
3436 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3438 FullName = msi_alloc(len*sizeof(WCHAR));
3439 strcpyW(FullName,ExeStr);
3440 strcatW( FullName, file->TargetPath );
3441 strcatW(FullName,close);
3443 TRACE("Registering %s\n",debugstr_w(FullName));
3444 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3445 &si, &info);
3447 if (brc)
3448 msi_dialog_check_messages(info.hProcess);
3450 msi_free(FullName);
3452 /* the UI chunk */
3453 uirow = MSI_CreateRecord( 2 );
3454 uipath = strdupW( file->TargetPath );
3455 p = strrchrW(uipath,'\\');
3456 if (p)
3457 p[1]=0;
3458 MSI_RecordSetStringW( uirow, 1, &p[2] );
3459 MSI_RecordSetStringW( uirow, 2, uipath);
3460 ui_actiondata( package, szSelfRegModules, uirow);
3461 msiobj_release( &uirow->hdr );
3462 msi_free( uipath );
3463 /* FIXME: call ui_progress? */
3465 return ERROR_SUCCESS;
3468 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3470 UINT rc;
3471 MSIQUERY * view;
3472 static const WCHAR ExecSeqQuery[] =
3473 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3474 '`','S','e','l','f','R','e','g','`',0};
3476 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3477 if (rc != ERROR_SUCCESS)
3479 TRACE("no SelfReg table\n");
3480 return ERROR_SUCCESS;
3483 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3484 msiobj_release(&view->hdr);
3486 return ERROR_SUCCESS;
3489 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3491 MSIFEATURE *feature;
3492 UINT rc;
3493 HKEY hkey=0;
3494 HKEY hukey=0;
3496 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3497 if (rc != ERROR_SUCCESS)
3498 goto end;
3500 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3501 if (rc != ERROR_SUCCESS)
3502 goto end;
3504 /* here the guids are base 85 encoded */
3505 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3507 ComponentList *cl;
3508 LPWSTR data = NULL;
3509 GUID clsid;
3510 INT size;
3511 BOOL absent = FALSE;
3512 MSIRECORD *uirow;
3514 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3515 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3516 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3517 absent = TRUE;
3519 size = 1;
3520 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3522 size += 21;
3524 if (feature->Feature_Parent)
3525 size += strlenW( feature->Feature_Parent )+2;
3527 data = msi_alloc(size * sizeof(WCHAR));
3529 data[0] = 0;
3530 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3532 MSICOMPONENT* component = cl->component;
3533 WCHAR buf[21];
3535 buf[0] = 0;
3536 if (component->ComponentId)
3538 TRACE("From %s\n",debugstr_w(component->ComponentId));
3539 CLSIDFromString(component->ComponentId, &clsid);
3540 encode_base85_guid(&clsid,buf);
3541 TRACE("to %s\n",debugstr_w(buf));
3542 strcatW(data,buf);
3545 if (feature->Feature_Parent)
3547 static const WCHAR sep[] = {'\2',0};
3548 strcatW(data,sep);
3549 strcatW(data,feature->Feature_Parent);
3552 msi_reg_set_val_str( hkey, feature->Feature, data );
3553 msi_free(data);
3555 size = 0;
3556 if (feature->Feature_Parent)
3557 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3558 if (!absent)
3560 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3561 (LPBYTE)feature->Feature_Parent,size);
3563 else
3565 size += 2*sizeof(WCHAR);
3566 data = msi_alloc(size);
3567 data[0] = 0x6;
3568 data[1] = 0;
3569 if (feature->Feature_Parent)
3570 strcpyW( &data[1], feature->Feature_Parent );
3571 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3572 (LPBYTE)data,size);
3573 msi_free(data);
3576 /* the UI chunk */
3577 uirow = MSI_CreateRecord( 1 );
3578 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3579 ui_actiondata( package, szPublishFeatures, uirow);
3580 msiobj_release( &uirow->hdr );
3581 /* FIXME: call ui_progress? */
3584 end:
3585 RegCloseKey(hkey);
3586 RegCloseKey(hukey);
3587 return rc;
3590 static UINT msi_get_local_package_name( LPWSTR path )
3592 static const WCHAR szInstaller[] = {
3593 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3594 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3595 DWORD time, len, i;
3596 HANDLE handle;
3598 time = GetTickCount();
3599 GetWindowsDirectoryW( path, MAX_PATH );
3600 lstrcatW( path, szInstaller );
3601 CreateDirectoryW( path, NULL );
3603 len = lstrlenW(path);
3604 for (i=0; i<0x10000; i++)
3606 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3607 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3608 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3609 if (handle != INVALID_HANDLE_VALUE)
3611 CloseHandle(handle);
3612 break;
3614 if (GetLastError() != ERROR_FILE_EXISTS &&
3615 GetLastError() != ERROR_SHARING_VIOLATION)
3616 return ERROR_FUNCTION_FAILED;
3619 return ERROR_SUCCESS;
3622 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3624 static const WCHAR szOriginalDatabase[] =
3625 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3626 WCHAR packagefile[MAX_PATH];
3627 LPWSTR msiFilePath;
3628 UINT r;
3630 r = msi_get_local_package_name( packagefile );
3631 if (r != ERROR_SUCCESS)
3632 return r;
3634 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3636 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3637 r = CopyFileW( msiFilePath, packagefile, FALSE);
3638 msi_free( msiFilePath );
3640 if (!r)
3642 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3643 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3644 return ERROR_FUNCTION_FAILED;
3647 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3648 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3649 return ERROR_SUCCESS;
3652 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3654 LPWSTR prop, val, key;
3655 static const LPCSTR propval[] = {
3656 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3657 "ARPCONTACT", "Contact",
3658 "ARPCOMMENTS", "Comments",
3659 "ProductName", "DisplayName",
3660 "ProductVersion", "DisplayVersion",
3661 "ARPHELPLINK", "HelpLink",
3662 "ARPHELPTELEPHONE", "HelpTelephone",
3663 "ARPINSTALLLOCATION", "InstallLocation",
3664 "SourceDir", "InstallSource",
3665 "Manufacturer", "Publisher",
3666 "ARPREADME", "Readme",
3667 "ARPSIZE", "Size",
3668 "ARPURLINFOABOUT", "URLInfoAbout",
3669 "ARPURLUPDATEINFO", "URLUpdateInfo",
3670 NULL,
3672 const LPCSTR *p = propval;
3674 while( *p )
3676 prop = strdupAtoW( *p++ );
3677 key = strdupAtoW( *p++ );
3678 val = msi_dup_property( package, prop );
3679 msi_reg_set_val_str( hkey, key, val );
3680 msi_free(val);
3681 msi_free(key);
3682 msi_free(prop);
3684 return ERROR_SUCCESS;
3687 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3689 HKEY hkey=0;
3690 LPWSTR buffer = NULL;
3691 UINT rc;
3692 DWORD size, langid;
3693 static const WCHAR szWindowsInstaller[] =
3694 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3695 static const WCHAR szUpgradeCode[] =
3696 {'U','p','g','r','a','d','e','C','o','d','e',0};
3697 static const WCHAR modpath_fmt[] =
3698 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3699 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3700 static const WCHAR szModifyPath[] =
3701 {'M','o','d','i','f','y','P','a','t','h',0};
3702 static const WCHAR szUninstallString[] =
3703 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3704 static const WCHAR szEstimatedSize[] =
3705 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3706 static const WCHAR szProductLanguage[] =
3707 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3708 static const WCHAR szProductVersion[] =
3709 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3711 SYSTEMTIME systime;
3712 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3713 LPWSTR upgrade_code;
3714 WCHAR szDate[9];
3716 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3717 if (rc != ERROR_SUCCESS)
3718 return rc;
3720 /* dump all the info i can grab */
3721 /* FIXME: Flesh out more information */
3723 msi_write_uninstall_property_vals( package, hkey );
3725 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3727 msi_make_package_local( package, hkey );
3729 /* do ModifyPath and UninstallString */
3730 size = deformat_string(package,modpath_fmt,&buffer);
3731 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3732 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3733 msi_free(buffer);
3735 /* FIXME: Write real Estimated Size when we have it */
3736 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3738 GetLocalTime(&systime);
3739 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3740 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3742 langid = msi_get_property_int( package, szProductLanguage, 0 );
3743 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3745 buffer = msi_dup_property( package, szProductVersion );
3746 if (buffer)
3748 DWORD verdword = msi_version_str_to_dword(buffer);
3750 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3751 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3752 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3754 msi_free(buffer);
3756 /* Handle Upgrade Codes */
3757 upgrade_code = msi_dup_property( package, szUpgradeCode );
3758 if (upgrade_code)
3760 HKEY hkey2;
3761 WCHAR squashed[33];
3762 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3763 squash_guid(package->ProductCode,squashed);
3764 msi_reg_set_val_str( hkey2, squashed, NULL );
3765 RegCloseKey(hkey2);
3766 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3767 squash_guid(package->ProductCode,squashed);
3768 msi_reg_set_val_str( hkey2, squashed, NULL );
3769 RegCloseKey(hkey2);
3771 msi_free(upgrade_code);
3774 RegCloseKey(hkey);
3776 /* FIXME: call ui_actiondata */
3778 return ERROR_SUCCESS;
3781 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3783 return execute_script(package,INSTALL_SCRIPT);
3786 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3788 UINT rc;
3790 /* turn off scheduleing */
3791 package->script->CurrentlyScripting= FALSE;
3793 /* first do the same as an InstallExecute */
3794 rc = ACTION_InstallExecute(package);
3795 if (rc != ERROR_SUCCESS)
3796 return rc;
3798 /* then handle Commit Actions */
3799 rc = execute_script(package,COMMIT_SCRIPT);
3801 return rc;
3804 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3806 static const WCHAR RunOnce[] = {
3807 'S','o','f','t','w','a','r','e','\\',
3808 'M','i','c','r','o','s','o','f','t','\\',
3809 'W','i','n','d','o','w','s','\\',
3810 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3811 'R','u','n','O','n','c','e',0};
3812 static const WCHAR InstallRunOnce[] = {
3813 'S','o','f','t','w','a','r','e','\\',
3814 'M','i','c','r','o','s','o','f','t','\\',
3815 'W','i','n','d','o','w','s','\\',
3816 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3817 'I','n','s','t','a','l','l','e','r','\\',
3818 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3820 static const WCHAR msiexec_fmt[] = {
3821 '%','s',
3822 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3823 '\"','%','s','\"',0};
3824 static const WCHAR install_fmt[] = {
3825 '/','I',' ','\"','%','s','\"',' ',
3826 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3827 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3828 WCHAR buffer[256], sysdir[MAX_PATH];
3829 HKEY hkey;
3830 WCHAR squished_pc[100];
3832 squash_guid(package->ProductCode,squished_pc);
3834 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3835 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3836 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3837 squished_pc);
3839 msi_reg_set_val_str( hkey, squished_pc, buffer );
3840 RegCloseKey(hkey);
3842 TRACE("Reboot command %s\n",debugstr_w(buffer));
3844 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3845 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3847 msi_reg_set_val_str( hkey, squished_pc, buffer );
3848 RegCloseKey(hkey);
3850 return ERROR_INSTALL_SUSPEND;
3853 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3855 DWORD attrib;
3856 UINT rc;
3858 * we are currently doing what should be done here in the top level Install
3859 * however for Adminastrative and uninstalls this step will be needed
3861 if (!package->PackagePath)
3862 return ERROR_SUCCESS;
3864 attrib = GetFileAttributesW(package->PackagePath);
3865 if (attrib == INVALID_FILE_ATTRIBUTES)
3867 LPWSTR prompt;
3868 LPWSTR msg;
3869 DWORD size = 0;
3871 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3872 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3873 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3874 if (rc == ERROR_MORE_DATA)
3876 prompt = msi_alloc(size * sizeof(WCHAR));
3877 MsiSourceListGetInfoW(package->ProductCode, NULL,
3878 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3879 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3881 else
3882 prompt = strdupW(package->PackagePath);
3884 msg = generate_error_string(package,1302,1,prompt);
3885 while(attrib == INVALID_FILE_ATTRIBUTES)
3887 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3888 if (rc == IDCANCEL)
3890 rc = ERROR_INSTALL_USEREXIT;
3891 break;
3893 attrib = GetFileAttributesW(package->PackagePath);
3895 msi_free(prompt);
3896 rc = ERROR_SUCCESS;
3898 else
3899 return ERROR_SUCCESS;
3901 return rc;
3904 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3906 HKEY hkey=0;
3907 LPWSTR buffer;
3908 LPWSTR productid;
3909 UINT rc,i;
3911 static const WCHAR szPropKeys[][80] =
3913 {'P','r','o','d','u','c','t','I','D',0},
3914 {'U','S','E','R','N','A','M','E',0},
3915 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3916 {0},
3919 static const WCHAR szRegKeys[][80] =
3921 {'P','r','o','d','u','c','t','I','D',0},
3922 {'R','e','g','O','w','n','e','r',0},
3923 {'R','e','g','C','o','m','p','a','n','y',0},
3924 {0},
3927 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3928 if (!productid)
3929 return ERROR_SUCCESS;
3931 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3932 if (rc != ERROR_SUCCESS)
3933 goto end;
3935 for( i = 0; szPropKeys[i][0]; i++ )
3937 buffer = msi_dup_property( package, szPropKeys[i] );
3938 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3939 msi_free( buffer );
3942 end:
3943 msi_free(productid);
3944 RegCloseKey(hkey);
3946 /* FIXME: call ui_actiondata */
3948 return ERROR_SUCCESS;
3952 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3954 UINT rc;
3956 package->script->InWhatSequence |= SEQUENCE_EXEC;
3957 rc = ACTION_ProcessExecSequence(package,FALSE);
3958 return rc;
3962 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3964 MSIPACKAGE *package = (MSIPACKAGE*)param;
3965 LPCWSTR compgroupid=NULL;
3966 LPCWSTR feature=NULL;
3967 LPCWSTR text = NULL;
3968 LPCWSTR qualifier = NULL;
3969 LPCWSTR component = NULL;
3970 LPWSTR advertise = NULL;
3971 LPWSTR output = NULL;
3972 HKEY hkey;
3973 UINT rc = ERROR_SUCCESS;
3974 MSICOMPONENT *comp;
3975 DWORD sz = 0;
3976 MSIRECORD *uirow;
3978 component = MSI_RecordGetString(rec,3);
3979 comp = get_loaded_component(package,component);
3981 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3982 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3983 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3985 TRACE("Skipping: Component %s not scheduled for install\n",
3986 debugstr_w(component));
3988 return ERROR_SUCCESS;
3991 compgroupid = MSI_RecordGetString(rec,1);
3992 qualifier = MSI_RecordGetString(rec,2);
3994 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
3995 if (rc != ERROR_SUCCESS)
3996 goto end;
3998 text = MSI_RecordGetString(rec,4);
3999 feature = MSI_RecordGetString(rec,5);
4001 advertise = create_component_advertise_string(package, comp, feature);
4003 sz = strlenW(advertise);
4005 if (text)
4006 sz += lstrlenW(text);
4008 sz+=3;
4009 sz *= sizeof(WCHAR);
4011 output = msi_alloc_zero(sz);
4012 strcpyW(output,advertise);
4013 msi_free(advertise);
4015 if (text)
4016 strcatW(output,text);
4018 msi_reg_set_val_multi_str( hkey, qualifier, output );
4020 end:
4021 RegCloseKey(hkey);
4022 msi_free(output);
4024 /* the UI chunk */
4025 uirow = MSI_CreateRecord( 2 );
4026 MSI_RecordSetStringW( uirow, 1, compgroupid );
4027 MSI_RecordSetStringW( uirow, 2, qualifier);
4028 ui_actiondata( package, szPublishComponents, uirow);
4029 msiobj_release( &uirow->hdr );
4030 /* FIXME: call ui_progress? */
4032 return rc;
4036 * At present I am ignorning the advertised components part of this and only
4037 * focusing on the qualified component sets
4039 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4041 UINT rc;
4042 MSIQUERY * view;
4043 static const WCHAR ExecSeqQuery[] =
4044 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4045 '`','P','u','b','l','i','s','h',
4046 'C','o','m','p','o','n','e','n','t','`',0};
4048 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4049 if (rc != ERROR_SUCCESS)
4050 return ERROR_SUCCESS;
4052 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4053 msiobj_release(&view->hdr);
4055 return rc;
4058 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4059 LPCSTR action, LPCWSTR table )
4061 static const WCHAR query[] = {
4062 'S','E','L','E','C','T',' ','*',' ',
4063 'F','R','O','M',' ','`','%','s','`',0 };
4064 MSIQUERY *view = NULL;
4065 DWORD count = 0;
4066 UINT r;
4068 r = MSI_OpenQuery( package->db, &view, query, table );
4069 if (r == ERROR_SUCCESS)
4071 r = MSI_IterateRecords(view, &count, NULL, package);
4072 msiobj_release(&view->hdr);
4075 if (count)
4076 FIXME("%s -> %u ignored %s table values\n",
4077 action, count, debugstr_w(table));
4079 return ERROR_SUCCESS;
4082 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4084 TRACE("%p\n", package);
4085 return ERROR_SUCCESS;
4088 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4090 static const WCHAR table[] =
4091 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4092 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4095 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4097 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4098 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4101 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4103 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4104 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4107 static UINT ACTION_BindImage( MSIPACKAGE *package )
4109 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4110 return msi_unimplemented_action_stub( package, "BindImage", table );
4113 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4115 static const WCHAR table[] = {
4116 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4117 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4120 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4122 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4123 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4126 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4128 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4129 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4132 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4134 static const WCHAR table[] = {
4135 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4136 return msi_unimplemented_action_stub( package, "InstallServices", table );
4139 static UINT ACTION_StartServices( MSIPACKAGE *package )
4141 static const WCHAR table[] = {
4142 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4143 return msi_unimplemented_action_stub( package, "StartServices", table );
4146 static UINT ACTION_StopServices( MSIPACKAGE *package )
4148 static const WCHAR table[] = {
4149 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4150 return msi_unimplemented_action_stub( package, "StopServices", table );
4153 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4155 static const WCHAR table[] = {
4156 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4157 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4160 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4162 static const WCHAR table[] = {
4163 'E','n','v','i','r','o','n','m','e','n','t',0 };
4164 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4167 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4169 static const WCHAR table[] = {
4170 'E','n','v','i','r','o','n','m','e','n','t',0 };
4171 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4174 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4176 static const WCHAR table[] = {
4177 'M','s','i','A','s','s','e','m','b','l','y',0 };
4178 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4181 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4183 static const WCHAR table[] = {
4184 'M','s','i','A','s','s','e','m','b','l','y',0 };
4185 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4188 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4190 static const WCHAR table[] = { 'F','o','n','t',0 };
4191 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4194 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4196 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4197 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4200 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4202 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4203 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4206 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4208 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4209 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4212 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4214 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4215 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4218 static struct _actions StandardActions[] = {
4219 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4220 { szAppSearch, ACTION_AppSearch },
4221 { szBindImage, ACTION_BindImage },
4222 { szCCPSearch, ACTION_CCPSearch},
4223 { szCostFinalize, ACTION_CostFinalize },
4224 { szCostInitialize, ACTION_CostInitialize },
4225 { szCreateFolders, ACTION_CreateFolders },
4226 { szCreateShortcuts, ACTION_CreateShortcuts },
4227 { szDeleteServices, ACTION_DeleteServices },
4228 { szDisableRollback, NULL},
4229 { szDuplicateFiles, ACTION_DuplicateFiles },
4230 { szExecuteAction, ACTION_ExecuteAction },
4231 { szFileCost, ACTION_FileCost },
4232 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4233 { szForceReboot, ACTION_ForceReboot },
4234 { szInstallAdminPackage, NULL},
4235 { szInstallExecute, ACTION_InstallExecute },
4236 { szInstallExecuteAgain, ACTION_InstallExecute },
4237 { szInstallFiles, ACTION_InstallFiles},
4238 { szInstallFinalize, ACTION_InstallFinalize },
4239 { szInstallInitialize, ACTION_InstallInitialize },
4240 { szInstallSFPCatalogFile, NULL},
4241 { szInstallValidate, ACTION_InstallValidate },
4242 { szIsolateComponents, ACTION_IsolateComponents },
4243 { szLaunchConditions, ACTION_LaunchConditions },
4244 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4245 { szMoveFiles, ACTION_MoveFiles },
4246 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4247 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4248 { szInstallODBC, NULL},
4249 { szInstallServices, ACTION_InstallServices },
4250 { szPatchFiles, ACTION_PatchFiles },
4251 { szProcessComponents, ACTION_ProcessComponents },
4252 { szPublishComponents, ACTION_PublishComponents },
4253 { szPublishFeatures, ACTION_PublishFeatures },
4254 { szPublishProduct, ACTION_PublishProduct },
4255 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4256 { szRegisterComPlus, ACTION_RegisterComPlus},
4257 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4258 { szRegisterFonts, ACTION_RegisterFonts },
4259 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4260 { szRegisterProduct, ACTION_RegisterProduct },
4261 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4262 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4263 { szRegisterUser, ACTION_RegisterUser},
4264 { szRemoveDuplicateFiles, NULL},
4265 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4266 { szRemoveExistingProducts, NULL},
4267 { szRemoveFiles, ACTION_RemoveFiles},
4268 { szRemoveFolders, NULL},
4269 { szRemoveIniValues, ACTION_RemoveIniValues },
4270 { szRemoveODBC, NULL},
4271 { szRemoveRegistryValues, NULL},
4272 { szRemoveShortcuts, NULL},
4273 { szResolveSource, ACTION_ResolveSource},
4274 { szRMCCPSearch, ACTION_RMCCPSearch},
4275 { szScheduleReboot, NULL},
4276 { szSelfRegModules, ACTION_SelfRegModules },
4277 { szSelfUnregModules, ACTION_SelfUnregModules },
4278 { szSetODBCFolders, NULL},
4279 { szStartServices, ACTION_StartServices },
4280 { szStopServices, ACTION_StopServices },
4281 { szUnpublishComponents, NULL},
4282 { szUnpublishFeatures, NULL},
4283 { szUnregisterClassInfo, NULL},
4284 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4285 { szUnregisterExtensionInfo, NULL},
4286 { szUnregisterFonts, ACTION_UnregisterFonts },
4287 { szUnregisterMIMEInfo, NULL},
4288 { szUnregisterProgIdInfo, NULL},
4289 { szUnregisterTypeLibraries, NULL},
4290 { szValidateProductID, NULL},
4291 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4292 { szWriteIniValues, ACTION_WriteIniValues },
4293 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4294 { NULL, NULL},