msi: Callers of alloc_msihandle should handle failure.
[wine/multimedia.git] / dlls / msi / action.c
blobda7d7e8ddcc746403722efcf5d03135be97706f6
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 LPWSTR p, *ret = NULL;
368 UINT count = 0;
370 if (!str)
371 return ret;
373 /* count the number of substrings */
374 for ( p = (LPWSTR)str, count = 0; p; count++ )
376 p = strchrW( p, sep );
377 if (p)
378 p++;
381 /* allocate space for an array of substring pointers and the substrings */
382 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
383 (lstrlenW(str)+1) * sizeof(WCHAR) );
384 if (!ret)
385 return ret;
387 /* copy the string and set the pointers */
388 p = (LPWSTR) &ret[count+1];
389 lstrcpyW( p, str );
390 for( count = 0; (ret[count] = p); count++ )
392 p = strchrW( p, sep );
393 if (p)
394 *p++ = 0;
397 return ret;
400 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
405 HRESULT r;
407 TRACE("%p %s\n", package, debugstr_w(name) );
409 if (*name++ != ':')
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
416 if (SUCCEEDED(r))
418 ret = msi_table_apply_transform( package->db, stg );
419 IStorage_Release( stg );
420 ret = ERROR_SUCCESS;
422 else
423 ERR("failed to open substorage %s\n", debugstr_w(name));
425 return ret;
428 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
430 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
431 LPWSTR guid_list, *guids, product_id;
432 UINT i, ret = ERROR_FUNCTION_FAILED;
434 product_id = msi_dup_property( package, szProdID );
435 if (!product_id)
437 /* FIXME: the property ProductID should be written into the DB somewhere */
438 ERR("no product ID to check\n");
439 return ERROR_SUCCESS;
442 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
443 guids = msi_split_string( guid_list, ';' );
444 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
446 if (!lstrcmpW( guids[i], product_id ))
447 ret = ERROR_SUCCESS;
449 msi_free( guids );
450 msi_free( guid_list );
451 msi_free( product_id );
453 return ret;
456 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
458 MSISUMMARYINFO *si;
459 LPWSTR str, *substorage;
460 UINT i, r = ERROR_SUCCESS;
462 si = MSI_GetSummaryInformationW( patch_db, 0 );
463 if (!si)
464 return ERROR_FUNCTION_FAILED;
466 msi_check_patch_applicable( package, si );
468 /* enumerate the substorage */
469 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
470 substorage = msi_split_string( str, ';' );
471 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
472 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
473 msi_free( substorage );
474 msi_free( str );
476 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
478 msiobj_release( &si->hdr );
480 return r;
483 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
485 MSIDATABASE *patch_db = NULL;
486 UINT r;
488 TRACE("%p %s\n", package, debugstr_w( file ) );
490 /* FIXME:
491 * We probably want to make sure we only open a patch collection here.
492 * Patch collections (.msp) and databases (.msi) have different GUIDs
493 * but currently MSI_OpenDatabaseW will accept both.
495 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
496 if ( r != ERROR_SUCCESS )
498 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
499 return r;
502 msi_parse_patch_summary( package, patch_db );
503 msiobj_release( &patch_db->hdr );
505 return ERROR_SUCCESS;
508 /* get the PATCH property, and apply all the patches it specifies */
509 static UINT msi_apply_patches( MSIPACKAGE *package )
511 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
512 LPWSTR patch_list, *patches;
513 UINT i, r = ERROR_SUCCESS;
515 patch_list = msi_dup_property( package, szPatch );
517 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
519 patches = msi_split_string( patch_list, ';' );
520 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
521 r = msi_apply_patch_package( package, patches[i] );
523 msi_free( patches );
524 msi_free( patch_list );
526 return r;
529 static UINT msi_apply_transforms( MSIPACKAGE *package )
531 static const WCHAR szTransforms[] = {
532 'T','R','A','N','S','F','O','R','M','S',0 };
533 LPWSTR xform_list, *xforms;
534 UINT i, r = ERROR_SUCCESS;
536 xform_list = msi_dup_property( package, szTransforms );
537 xforms = msi_split_string( xform_list, ';' );
539 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
541 if (xforms[i][0] == ':')
542 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
543 else
544 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
547 msi_free( xforms );
548 msi_free( xform_list );
550 return r;
553 /****************************************************
554 * TOP level entry points
555 *****************************************************/
557 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
558 LPCWSTR szCommandLine )
560 UINT rc;
561 BOOL ui = FALSE;
562 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
563 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
564 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
566 MSI_SetPropertyW(package, szAction, szInstall);
568 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
570 package->script->InWhatSequence = SEQUENCE_INSTALL;
572 if (szPackagePath)
574 LPWSTR p, check, path;
576 package->PackagePath = strdupW(szPackagePath);
577 path = strdupW(szPackagePath);
578 p = strrchrW(path,'\\');
579 if (p)
581 p++;
582 *p=0;
584 else
586 msi_free(path);
587 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
588 GetCurrentDirectoryW(MAX_PATH,path);
589 strcatW(path,cszbs);
592 check = msi_dup_property( package, cszSourceDir );
593 if (!check)
594 MSI_SetPropertyW(package, cszSourceDir, path);
595 msi_free(check);
596 msi_free(path);
599 msi_parse_command_line( package, szCommandLine );
601 msi_apply_transforms( package );
602 msi_apply_patches( package );
604 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
606 package->script->InWhatSequence |= SEQUENCE_UI;
607 rc = ACTION_ProcessUISequence(package);
608 ui = TRUE;
609 if (rc == ERROR_SUCCESS)
611 package->script->InWhatSequence |= SEQUENCE_EXEC;
612 rc = ACTION_ProcessExecSequence(package,TRUE);
615 else
616 rc = ACTION_ProcessExecSequence(package,FALSE);
618 if (rc == -1)
620 /* install was halted but should be considered a success */
621 rc = ERROR_SUCCESS;
624 package->script->CurrentlyScripting= FALSE;
626 /* process the ending type action */
627 if (rc == ERROR_SUCCESS)
628 ACTION_PerformActionSequence(package,-1,ui);
629 else if (rc == ERROR_INSTALL_USEREXIT)
630 ACTION_PerformActionSequence(package,-2,ui);
631 else if (rc == ERROR_INSTALL_SUSPEND)
632 ACTION_PerformActionSequence(package,-4,ui);
633 else /* failed */
634 ACTION_PerformActionSequence(package,-3,ui);
636 /* finish up running custom actions */
637 ACTION_FinishCustomActions(package);
639 return rc;
642 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
644 UINT rc = ERROR_SUCCESS;
645 MSIRECORD * row = 0;
646 static const WCHAR ExecSeqQuery[] =
647 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
648 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
649 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
650 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
652 static const WCHAR UISeqQuery[] =
653 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
654 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
655 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
656 ' ', '=',' ','%','i',0};
658 if (UI)
659 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
660 else
661 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
663 if (row)
665 LPCWSTR action, cond;
667 TRACE("Running the actions\n");
669 /* check conditions */
670 cond = MSI_RecordGetString(row,2);
671 if (cond)
673 /* this is a hack to skip errors in the condition code */
674 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
675 goto end;
678 action = MSI_RecordGetString(row,1);
679 if (!action)
681 ERR("failed to fetch action\n");
682 rc = ERROR_FUNCTION_FAILED;
683 goto end;
686 if (UI)
687 rc = ACTION_PerformUIAction(package,action);
688 else
689 rc = ACTION_PerformAction(package,action,FALSE);
690 end:
691 msiobj_release(&row->hdr);
693 else
694 rc = ERROR_SUCCESS;
696 return rc;
699 typedef struct {
700 MSIPACKAGE* package;
701 BOOL UI;
702 } iterate_action_param;
704 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
706 iterate_action_param *iap= (iterate_action_param*)param;
707 UINT rc;
708 LPCWSTR cond, action;
710 action = MSI_RecordGetString(row,1);
711 if (!action)
713 ERR("Error is retrieving action name\n");
714 return ERROR_FUNCTION_FAILED;
717 /* check conditions */
718 cond = MSI_RecordGetString(row,2);
719 if (cond)
721 /* this is a hack to skip errors in the condition code */
722 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
724 TRACE("Skipping action: %s (condition is false)\n",
725 debugstr_w(action));
726 return ERROR_SUCCESS;
730 if (iap->UI)
731 rc = ACTION_PerformUIAction(iap->package,action);
732 else
733 rc = ACTION_PerformAction(iap->package,action,FALSE);
735 msi_dialog_check_messages( NULL );
737 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
738 rc = iap->package->CurrentInstallState;
740 if (rc == ERROR_FUNCTION_NOT_CALLED)
741 rc = ERROR_SUCCESS;
743 if (rc != ERROR_SUCCESS)
744 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
746 return rc;
749 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
751 MSIQUERY * view;
752 UINT r;
753 static const WCHAR query[] =
754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
755 '`','%','s','`',
756 ' ','W','H','E','R','E',' ',
757 '`','S','e','q','u','e','n','c','e','`',' ',
758 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
759 '`','S','e','q','u','e','n','c','e','`',0};
760 iterate_action_param iap;
763 * FIXME: probably should be checking UILevel in the
764 * ACTION_PerformUIAction/ACTION_PerformAction
765 * rather than saving the UI level here. Those
766 * two functions can be merged too.
768 iap.package = package;
769 iap.UI = TRUE;
771 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
773 r = MSI_OpenQuery( package->db, &view, query, szTable );
774 if (r == ERROR_SUCCESS)
776 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
777 msiobj_release(&view->hdr);
780 return r;
783 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
785 MSIQUERY * view;
786 UINT rc;
787 static const WCHAR ExecSeqQuery[] =
788 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
789 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
790 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
792 'O','R','D','E','R',' ', 'B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0 };
794 MSIRECORD * row = 0;
795 static const WCHAR IVQuery[] =
796 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
797 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
798 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
799 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
800 ' ','\'', 'I','n','s','t','a','l','l',
801 'V','a','l','i','d','a','t','e','\'', 0};
802 INT seq = 0;
803 iterate_action_param iap;
805 iap.package = package;
806 iap.UI = FALSE;
808 if (package->script->ExecuteSequenceRun)
810 TRACE("Execute Sequence already Run\n");
811 return ERROR_SUCCESS;
814 package->script->ExecuteSequenceRun = TRUE;
816 /* get the sequence number */
817 if (UIran)
819 row = MSI_QueryGetRecord(package->db, IVQuery);
820 if( !row )
821 return ERROR_FUNCTION_FAILED;
822 seq = MSI_RecordGetInteger(row,1);
823 msiobj_release(&row->hdr);
826 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
827 if (rc == ERROR_SUCCESS)
829 TRACE("Running the actions\n");
831 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
832 msiobj_release(&view->hdr);
835 return rc;
838 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
840 MSIQUERY * view;
841 UINT rc;
842 static const WCHAR ExecSeqQuery [] =
843 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
844 '`','I','n','s','t','a','l','l',
845 'U','I','S','e','q','u','e','n','c','e','`',
846 ' ','W','H','E','R','E',' ',
847 '`','S','e','q','u','e','n','c','e','`',' ',
848 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
849 '`','S','e','q','u','e','n','c','e','`',0};
850 iterate_action_param iap;
852 iap.package = package;
853 iap.UI = TRUE;
855 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
857 if (rc == ERROR_SUCCESS)
859 TRACE("Running the actions\n");
861 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
862 msiobj_release(&view->hdr);
865 return rc;
868 /********************************************************
869 * ACTION helper functions and functions that perform the actions
870 *******************************************************/
871 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
872 UINT* rc, BOOL force )
874 BOOL ret = FALSE;
875 BOOL run = force;
876 int i;
878 if (!run && !package->script->CurrentlyScripting)
879 run = TRUE;
881 if (!run)
883 if (strcmpW(action,szInstallFinalize) == 0 ||
884 strcmpW(action,szInstallExecute) == 0 ||
885 strcmpW(action,szInstallExecuteAgain) == 0)
886 run = TRUE;
889 i = 0;
890 while (StandardActions[i].action != NULL)
892 if (strcmpW(StandardActions[i].action, action)==0)
894 if (!run)
896 ui_actioninfo(package, action, TRUE, 0);
897 *rc = schedule_action(package,INSTALL_SCRIPT,action);
898 ui_actioninfo(package, action, FALSE, *rc);
900 else
902 ui_actionstart(package, action);
903 if (StandardActions[i].handler)
905 *rc = StandardActions[i].handler(package);
907 else
909 FIXME("unhandled standard action %s\n",debugstr_w(action));
910 *rc = ERROR_SUCCESS;
913 ret = TRUE;
914 break;
916 i++;
918 return ret;
921 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
922 UINT* rc, BOOL force )
924 BOOL ret=FALSE;
925 UINT arc;
927 arc = ACTION_CustomAction(package,action, force);
929 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
931 *rc = arc;
932 ret = TRUE;
934 return ret;
938 * A lot of actions are really important even if they don't do anything
939 * explicit... Lots of properties are set at the beginning of the installation
940 * CostFinalize does a bunch of work to translate the directories and such
942 * But until I get write access to the database that is hard, so I am going to
943 * hack it to see if I can get something to run.
945 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
947 UINT rc = ERROR_SUCCESS;
948 BOOL handled;
950 TRACE("Performing action (%s)\n",debugstr_w(action));
952 handled = ACTION_HandleStandardAction(package, action, &rc, force);
954 if (!handled)
955 handled = ACTION_HandleCustomAction(package, action, &rc, force);
957 if (!handled)
959 FIXME("unhandled msi action %s\n",debugstr_w(action));
960 rc = ERROR_FUNCTION_NOT_CALLED;
963 return rc;
966 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
968 UINT rc = ERROR_SUCCESS;
969 BOOL handled = FALSE;
971 TRACE("Performing action (%s)\n",debugstr_w(action));
973 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
975 if (!handled)
976 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
978 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
979 handled = TRUE;
981 if (!handled)
983 FIXME("unhandled msi action %s\n",debugstr_w(action));
984 rc = ERROR_FUNCTION_NOT_CALLED;
987 return rc;
992 * Actual Action Handlers
995 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
997 MSIPACKAGE *package = (MSIPACKAGE*)param;
998 LPCWSTR dir;
999 LPWSTR full_path;
1000 MSIRECORD *uirow;
1001 MSIFOLDER *folder;
1003 dir = MSI_RecordGetString(row,1);
1004 if (!dir)
1006 ERR("Unable to get folder id\n");
1007 return ERROR_SUCCESS;
1010 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1011 if (!full_path)
1013 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1014 return ERROR_SUCCESS;
1017 TRACE("Folder is %s\n",debugstr_w(full_path));
1019 /* UI stuff */
1020 uirow = MSI_CreateRecord(1);
1021 MSI_RecordSetStringW(uirow,1,full_path);
1022 ui_actiondata(package,szCreateFolders,uirow);
1023 msiobj_release( &uirow->hdr );
1025 if (folder->State == 0)
1026 create_full_pathW(full_path);
1028 folder->State = 3;
1030 msi_free(full_path);
1031 return ERROR_SUCCESS;
1034 /* FIXME: probably should merge this with the above function */
1035 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1037 UINT rc = ERROR_SUCCESS;
1038 MSIFOLDER *folder;
1039 LPWSTR install_path;
1041 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1042 if (!install_path)
1043 return ERROR_FUNCTION_FAILED;
1045 /* create the path */
1046 if (folder->State == 0)
1048 create_full_pathW(install_path);
1049 folder->State = 2;
1051 msi_free(install_path);
1053 return rc;
1056 UINT msi_create_component_directories( MSIPACKAGE *package )
1058 MSICOMPONENT *comp;
1060 /* create all the folders required by the components are going to install */
1061 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1063 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1064 continue;
1065 msi_create_directory( package, comp->Directory );
1068 return ERROR_SUCCESS;
1072 * Also we cannot enable/disable components either, so for now I am just going
1073 * to do all the directories for all the components.
1075 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1077 static const WCHAR ExecSeqQuery[] =
1078 {'S','E','L','E','C','T',' ',
1079 '`','D','i','r','e','c','t','o','r','y','_','`',
1080 ' ','F','R','O','M',' ',
1081 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1082 UINT rc;
1083 MSIQUERY *view;
1085 /* create all the empty folders specified in the CreateFolder table */
1086 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1087 if (rc != ERROR_SUCCESS)
1088 return ERROR_SUCCESS;
1090 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1091 msiobj_release(&view->hdr);
1093 msi_create_component_directories( package );
1095 return rc;
1098 static UINT load_component( MSIRECORD *row, LPVOID param )
1100 MSIPACKAGE *package = param;
1101 MSICOMPONENT *comp;
1103 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1104 if (!comp)
1105 return ERROR_FUNCTION_FAILED;
1107 list_add_tail( &package->components, &comp->entry );
1109 /* fill in the data */
1110 comp->Component = msi_dup_record_field( row, 1 );
1112 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1114 comp->ComponentId = msi_dup_record_field( row, 2 );
1115 comp->Directory = msi_dup_record_field( row, 3 );
1116 comp->Attributes = MSI_RecordGetInteger(row,4);
1117 comp->Condition = msi_dup_record_field( row, 5 );
1118 comp->KeyPath = msi_dup_record_field( row, 6 );
1120 comp->Installed = INSTALLSTATE_ABSENT;
1122 switch (comp->Attributes)
1124 case msidbComponentAttributesLocalOnly:
1125 comp->Action = INSTALLSTATE_LOCAL;
1126 comp->ActionRequest = INSTALLSTATE_LOCAL;
1127 break;
1128 case msidbComponentAttributesSourceOnly:
1129 comp->Action = INSTALLSTATE_SOURCE;
1130 comp->ActionRequest = INSTALLSTATE_SOURCE;
1131 break;
1132 case msidbComponentAttributesOptional:
1133 comp->Action = INSTALLSTATE_DEFAULT;
1134 comp->ActionRequest = INSTALLSTATE_DEFAULT;
1135 break;
1136 default:
1137 comp->Action = INSTALLSTATE_LOCAL;
1138 comp->ActionRequest = INSTALLSTATE_LOCAL;
1141 return ERROR_SUCCESS;
1144 static UINT load_all_components( MSIPACKAGE *package )
1146 static const WCHAR query[] = {
1147 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1148 '`','C','o','m','p','o','n','e','n','t','`',0 };
1149 MSIQUERY *view;
1150 UINT r;
1152 if (!list_empty(&package->components))
1153 return ERROR_SUCCESS;
1155 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1156 if (r != ERROR_SUCCESS)
1157 return r;
1159 r = MSI_IterateRecords(view, NULL, load_component, package);
1160 msiobj_release(&view->hdr);
1161 return r;
1164 typedef struct {
1165 MSIPACKAGE *package;
1166 MSIFEATURE *feature;
1167 } _ilfs;
1169 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1171 ComponentList *cl;
1173 cl = msi_alloc( sizeof (*cl) );
1174 if ( !cl )
1175 return ERROR_NOT_ENOUGH_MEMORY;
1176 cl->component = comp;
1177 list_add_tail( &feature->Components, &cl->entry );
1179 return ERROR_SUCCESS;
1182 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1184 _ilfs* ilfs= (_ilfs*)param;
1185 LPCWSTR component;
1186 MSICOMPONENT *comp;
1188 component = MSI_RecordGetString(row,1);
1190 /* check to see if the component is already loaded */
1191 comp = get_loaded_component( ilfs->package, component );
1192 if (!comp)
1194 ERR("unknown component %s\n", debugstr_w(component));
1195 return ERROR_FUNCTION_FAILED;
1198 add_feature_component( ilfs->feature, comp );
1199 comp->Enabled = TRUE;
1201 return ERROR_SUCCESS;
1204 static UINT load_feature(MSIRECORD * row, LPVOID param)
1206 MSIPACKAGE* package = (MSIPACKAGE*)param;
1207 MSIFEATURE* feature;
1208 static const WCHAR Query1[] =
1209 {'S','E','L','E','C','T',' ',
1210 '`','C','o','m','p','o','n','e','n','t','_','`',
1211 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1212 'C','o','m','p','o','n','e','n','t','s','`',' ',
1213 'W','H','E','R','E',' ',
1214 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1215 MSIQUERY * view;
1216 UINT rc;
1217 _ilfs ilfs;
1219 /* fill in the data */
1221 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1222 if (!feature)
1223 return ERROR_NOT_ENOUGH_MEMORY;
1225 list_init( &feature->Components );
1227 feature->Feature = msi_dup_record_field( row, 1 );
1229 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1231 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1232 feature->Title = msi_dup_record_field( row, 3 );
1233 feature->Description = msi_dup_record_field( row, 4 );
1235 if (!MSI_RecordIsNull(row,5))
1236 feature->Display = MSI_RecordGetInteger(row,5);
1238 feature->Level= MSI_RecordGetInteger(row,6);
1239 feature->Directory = msi_dup_record_field( row, 7 );
1240 feature->Attributes = MSI_RecordGetInteger(row,8);
1242 feature->Installed = INSTALLSTATE_ABSENT;
1243 feature->Action = INSTALLSTATE_UNKNOWN;
1244 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1246 list_add_tail( &package->features, &feature->entry );
1248 /* load feature components */
1250 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1251 if (rc != ERROR_SUCCESS)
1252 return ERROR_SUCCESS;
1254 ilfs.package = package;
1255 ilfs.feature = feature;
1257 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1258 msiobj_release(&view->hdr);
1260 return ERROR_SUCCESS;
1263 static UINT load_all_features( MSIPACKAGE *package )
1265 static const WCHAR query[] = {
1266 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1267 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1268 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1269 MSIQUERY *view;
1270 UINT r;
1272 if (!list_empty(&package->features))
1273 return ERROR_SUCCESS;
1275 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1276 if (r != ERROR_SUCCESS)
1277 return r;
1279 r = MSI_IterateRecords( view, NULL, load_feature, package );
1280 msiobj_release( &view->hdr );
1281 return r;
1284 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1286 if (!p)
1287 return p;
1288 p = strchrW(p, ch);
1289 if (!p)
1290 return p;
1291 *p = 0;
1292 return p+1;
1295 static UINT load_file(MSIRECORD *row, LPVOID param)
1297 MSIPACKAGE* package = (MSIPACKAGE*)param;
1298 LPCWSTR component;
1299 MSIFILE *file;
1301 /* fill in the data */
1303 file = msi_alloc_zero( sizeof (MSIFILE) );
1304 if (!file)
1305 return ERROR_NOT_ENOUGH_MEMORY;
1307 file->File = msi_dup_record_field( row, 1 );
1309 component = MSI_RecordGetString( row, 2 );
1310 file->Component = get_loaded_component( package, component );
1312 if (!file->Component)
1313 ERR("Unfound Component %s\n",debugstr_w(component));
1315 file->FileName = msi_dup_record_field( row, 3 );
1316 reduce_to_longfilename( file->FileName );
1318 file->ShortName = msi_dup_record_field( row, 3 );
1319 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1321 file->FileSize = MSI_RecordGetInteger( row, 4 );
1322 file->Version = msi_dup_record_field( row, 5 );
1323 file->Language = msi_dup_record_field( row, 6 );
1324 file->Attributes = MSI_RecordGetInteger( row, 7 );
1325 file->Sequence = MSI_RecordGetInteger( row, 8 );
1327 file->state = msifs_invalid;
1329 /* if the compressed bits are not set in the file attributes,
1330 * then read the information from the package word count property
1332 if (file->Attributes & msidbFileAttributesCompressed)
1334 file->IsCompressed = TRUE;
1336 else if (file->Attributes & msidbFileAttributesNoncompressed)
1338 file->IsCompressed = FALSE;
1340 else
1342 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1345 if (file->IsCompressed)
1347 file->Component->ForceLocalState = TRUE;
1348 file->Component->Action = INSTALLSTATE_LOCAL;
1349 file->Component->ActionRequest = INSTALLSTATE_LOCAL;
1352 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1354 list_add_tail( &package->files, &file->entry );
1356 return ERROR_SUCCESS;
1359 static UINT load_all_files(MSIPACKAGE *package)
1361 MSIQUERY * view;
1362 UINT rc;
1363 static const WCHAR Query[] =
1364 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1365 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1366 '`','S','e','q','u','e','n','c','e','`', 0};
1368 if (!list_empty(&package->files))
1369 return ERROR_SUCCESS;
1371 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1372 if (rc != ERROR_SUCCESS)
1373 return ERROR_SUCCESS;
1375 rc = MSI_IterateRecords(view, NULL, load_file, package);
1376 msiobj_release(&view->hdr);
1378 return ERROR_SUCCESS;
1383 * I am not doing any of the costing functionality yet.
1384 * Mostly looking at doing the Component and Feature loading
1386 * The native MSI does A LOT of modification to tables here. Mostly adding
1387 * a lot of temporary columns to the Feature and Component tables.
1389 * note: Native msi also tracks the short filename. But I am only going to
1390 * track the long ones. Also looking at this directory table
1391 * it appears that the directory table does not get the parents
1392 * resolved base on property only based on their entries in the
1393 * directory table.
1395 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1397 static const WCHAR szCosting[] =
1398 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1399 static const WCHAR szZero[] = { '0', 0 };
1401 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1402 return ERROR_SUCCESS;
1404 MSI_SetPropertyW(package, szCosting, szZero);
1405 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1407 load_all_components( package );
1408 load_all_features( package );
1409 load_all_files( package );
1411 return ERROR_SUCCESS;
1414 static UINT execute_script(MSIPACKAGE *package, UINT script )
1416 int i;
1417 UINT rc = ERROR_SUCCESS;
1419 TRACE("Executing Script %i\n",script);
1421 if (!package->script)
1423 ERR("no script!\n");
1424 return ERROR_FUNCTION_FAILED;
1427 for (i = 0; i < package->script->ActionCount[script]; i++)
1429 LPWSTR action;
1430 action = package->script->Actions[script][i];
1431 ui_actionstart(package, action);
1432 TRACE("Executing Action (%s)\n",debugstr_w(action));
1433 rc = ACTION_PerformAction(package, action, TRUE);
1434 msi_free(package->script->Actions[script][i]);
1435 if (rc != ERROR_SUCCESS)
1436 break;
1438 msi_free(package->script->Actions[script]);
1440 package->script->ActionCount[script] = 0;
1441 package->script->Actions[script] = NULL;
1442 return rc;
1445 static UINT ACTION_FileCost(MSIPACKAGE *package)
1447 return ERROR_SUCCESS;
1450 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1452 static const WCHAR Query[] =
1453 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1454 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1455 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1456 ' ','=',' ','\'','%','s','\'',
1458 static const WCHAR szDot[] = { '.',0 };
1459 static WCHAR szEmpty[] = { 0 };
1460 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1461 LPCWSTR parent;
1462 MSIRECORD *row;
1463 MSIFOLDER *folder;
1465 TRACE("Looking for dir %s\n",debugstr_w(dir));
1467 folder = get_loaded_folder( package, dir );
1468 if (folder)
1469 return folder;
1471 TRACE("Working to load %s\n",debugstr_w(dir));
1473 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1474 if (!folder)
1475 return NULL;
1477 folder->Directory = strdupW(dir);
1479 row = MSI_QueryGetRecord(package->db, Query, dir);
1480 if (!row)
1481 return NULL;
1483 p = msi_dup_record_field(row, 3);
1485 /* split src and target dir */
1486 tgt_short = p;
1487 src_short = folder_split_path( p, ':' );
1489 /* split the long and short paths */
1490 tgt_long = folder_split_path( tgt_short, '|' );
1491 src_long = folder_split_path( src_short, '|' );
1493 /* check for no-op dirs */
1494 if (!lstrcmpW(szDot, tgt_short))
1495 tgt_short = szEmpty;
1496 if (!lstrcmpW(szDot, src_short))
1497 src_short = szEmpty;
1499 if (!tgt_long)
1500 tgt_long = tgt_short;
1502 if (!src_short) {
1503 src_short = tgt_short;
1504 src_long = tgt_long;
1507 if (!src_long)
1508 src_long = src_short;
1510 /* FIXME: use the target short path too */
1511 folder->TargetDefault = strdupW(tgt_long);
1512 folder->SourceShortPath = strdupW(src_short);
1513 folder->SourceLongPath = strdupW(src_long);
1514 msi_free(p);
1516 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1517 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1518 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1520 parent = MSI_RecordGetString(row, 2);
1521 if (parent)
1523 folder->Parent = load_folder( package, parent );
1524 if ( folder->Parent )
1525 TRACE("loaded parent %p %s\n", folder->Parent,
1526 debugstr_w(folder->Parent->Directory));
1527 else
1528 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1531 folder->Property = msi_dup_property( package, dir );
1533 msiobj_release(&row->hdr);
1535 list_add_tail( &package->folders, &folder->entry );
1537 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1539 return folder;
1542 /* scan for and update current install states */
1543 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1545 MSICOMPONENT *comp;
1546 MSIFEATURE *feature;
1548 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1550 INSTALLSTATE res;
1551 res = MsiGetComponentPathW( package->ProductCode,
1552 comp->ComponentId, NULL, NULL);
1553 if (res < 0)
1554 res = INSTALLSTATE_ABSENT;
1555 comp->Installed = res;
1558 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1560 ComponentList *cl;
1561 INSTALLSTATE res = -10;
1563 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1565 comp= cl->component;
1567 if (res == -10)
1568 res = comp->Installed;
1569 else
1571 if (res == comp->Installed)
1572 continue;
1574 if (res != comp->Installed)
1575 res = INSTALLSTATE_INCOMPLETE;
1578 feature->Installed = res;
1582 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1583 INSTALLSTATE state)
1585 static const WCHAR all[]={'A','L','L',0};
1586 LPWSTR override;
1587 MSIFEATURE *feature;
1589 override = msi_dup_property( package, property );
1590 if (!override)
1591 return FALSE;
1593 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1595 if (strcmpiW(override,all)==0)
1597 feature->ActionRequest= state;
1598 feature->Action = state;
1600 else
1602 LPWSTR ptr = override;
1603 LPWSTR ptr2 = strchrW(override,',');
1605 while (ptr)
1607 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1608 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1610 feature->ActionRequest= state;
1611 feature->Action = state;
1612 break;
1614 if (ptr2)
1616 ptr=ptr2+1;
1617 ptr2 = strchrW(ptr,',');
1619 else
1620 break;
1624 msi_free(override);
1626 return TRUE;
1629 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1631 int install_level;
1632 static const WCHAR szlevel[] =
1633 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1634 static const WCHAR szAddLocal[] =
1635 {'A','D','D','L','O','C','A','L',0};
1636 static const WCHAR szRemove[] =
1637 {'R','E','M','O','V','E',0};
1638 static const WCHAR szReinstall[] =
1639 {'R','E','I','N','S','T','A','L','L',0};
1640 BOOL override = FALSE;
1641 MSICOMPONENT* component;
1642 MSIFEATURE *feature;
1645 /* I do not know if this is where it should happen.. but */
1647 TRACE("Checking Install Level\n");
1649 install_level = msi_get_property_int( package, szlevel, 1 );
1651 /* ok hereis the _real_ rub
1652 * all these activation/deactivation things happen in order and things
1653 * later on the list override things earlier on the list.
1654 * 1) INSTALLLEVEL processing
1655 * 2) ADDLOCAL
1656 * 3) REMOVE
1657 * 4) ADDSOURCE
1658 * 5) ADDDEFAULT
1659 * 6) REINSTALL
1660 * 7) COMPADDLOCAL
1661 * 8) COMPADDSOURCE
1662 * 9) FILEADDLOCAL
1663 * 10) FILEADDSOURCE
1664 * 11) FILEADDDEFAULT
1665 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1666 * ignored for all the features. seems strange, especially since it is not
1667 * documented anywhere, but it is how it works.
1669 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1670 * REMOVE are the big ones, since we don't handle administrative installs
1671 * yet anyway.
1673 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1674 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1675 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1677 if (!override)
1679 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1681 BOOL feature_state = ((feature->Level > 0) &&
1682 (feature->Level <= install_level));
1684 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1686 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1688 feature->ActionRequest = INSTALLSTATE_SOURCE;
1689 feature->Action = INSTALLSTATE_SOURCE;
1691 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1693 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1694 feature->Action = INSTALLSTATE_ADVERTISED;
1696 else
1698 feature->ActionRequest = INSTALLSTATE_LOCAL;
1699 feature->Action = INSTALLSTATE_LOCAL;
1704 else
1706 /* set the Preselected Property */
1707 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1708 static const WCHAR szOne[] = { '1', 0 };
1710 MSI_SetPropertyW(package,szPreselected,szOne);
1714 * now we want to enable or disable components base on feature
1717 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1719 ComponentList *cl;
1721 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1722 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1723 feature->ActionRequest);
1725 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1727 component = cl->component;
1729 if (!component->Enabled)
1731 component->Action = INSTALLSTATE_UNKNOWN;
1732 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1734 else
1736 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1738 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1740 component->Action = INSTALLSTATE_LOCAL;
1741 component->ActionRequest = INSTALLSTATE_LOCAL;
1744 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1746 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1747 (component->Action == INSTALLSTATE_ABSENT) ||
1748 (component->Action == INSTALLSTATE_ADVERTISED) ||
1749 (component->Action == INSTALLSTATE_DEFAULT))
1752 component->Action = INSTALLSTATE_SOURCE;
1753 component->ActionRequest = INSTALLSTATE_SOURCE;
1756 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1758 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1759 (component->Action == INSTALLSTATE_ABSENT))
1762 component->Action = INSTALLSTATE_ADVERTISED;
1763 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1766 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1768 if (component->Action == INSTALLSTATE_UNKNOWN)
1770 component->Action = INSTALLSTATE_ABSENT;
1771 component->ActionRequest = INSTALLSTATE_ABSENT;
1776 if (component->ForceLocalState)
1778 feature->Action = INSTALLSTATE_LOCAL;
1779 feature->ActionRequest = INSTALLSTATE_LOCAL;
1784 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1786 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1787 debugstr_w(component->Component), component->Installed,
1788 component->Action, component->ActionRequest);
1792 return ERROR_SUCCESS;
1795 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1797 MSIPACKAGE *package = (MSIPACKAGE*)param;
1798 LPCWSTR name;
1799 LPWSTR path;
1801 name = MSI_RecordGetString(row,1);
1803 /* This helper function now does ALL the work */
1804 TRACE("Dir %s ...\n",debugstr_w(name));
1805 load_folder(package,name);
1806 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1807 TRACE("resolves to %s\n",debugstr_w(path));
1808 msi_free(path);
1810 return ERROR_SUCCESS;
1813 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1815 MSIPACKAGE *package = (MSIPACKAGE*)param;
1816 LPCWSTR name;
1817 MSIFEATURE *feature;
1819 name = MSI_RecordGetString( row, 1 );
1821 feature = get_loaded_feature( package, name );
1822 if (!feature)
1823 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1824 else
1826 LPCWSTR Condition;
1827 Condition = MSI_RecordGetString(row,3);
1829 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1831 int level = MSI_RecordGetInteger(row,2);
1832 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1833 feature->Level = level;
1836 return ERROR_SUCCESS;
1841 * A lot is done in this function aside from just the costing.
1842 * The costing needs to be implemented at some point but for now I am going
1843 * to focus on the directory building
1846 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1848 static const WCHAR ExecSeqQuery[] =
1849 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1850 '`','D','i','r','e','c','t','o','r','y','`',0};
1851 static const WCHAR ConditionQuery[] =
1852 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1853 '`','C','o','n','d','i','t','i','o','n','`',0};
1854 static const WCHAR szCosting[] =
1855 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1856 static const WCHAR szlevel[] =
1857 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1858 static const WCHAR szOne[] = { '1', 0 };
1859 MSICOMPONENT *comp;
1860 MSIFILE *file;
1861 UINT rc;
1862 MSIQUERY * view;
1863 LPWSTR level;
1865 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1866 return ERROR_SUCCESS;
1868 TRACE("Building Directory properties\n");
1870 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1871 if (rc == ERROR_SUCCESS)
1873 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1874 package);
1875 msiobj_release(&view->hdr);
1878 TRACE("File calculations\n");
1880 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1882 MSICOMPONENT* comp = file->Component;
1883 LPWSTR p;
1885 if (!comp)
1886 continue;
1888 /* calculate target */
1889 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1891 msi_free(file->TargetPath);
1893 TRACE("file %s is named %s\n",
1894 debugstr_w(file->File),debugstr_w(file->FileName));
1896 file->TargetPath = build_directory_name(2, p, file->FileName);
1898 msi_free(p);
1900 TRACE("file %s resolves to %s\n",
1901 debugstr_w(file->File),debugstr_w(file->TargetPath));
1903 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1905 file->state = msifs_missing;
1906 comp->Cost += file->FileSize;
1907 continue;
1910 if (file->Version)
1912 DWORD handle;
1913 DWORD versize;
1914 UINT sz;
1915 LPVOID version;
1916 static WCHAR name[] = {'\\',0};
1917 static const WCHAR name_fmt[] =
1918 {'%','u','.','%','u','.','%','u','.','%','u',0};
1919 WCHAR filever[0x100];
1920 VS_FIXEDFILEINFO *lpVer;
1922 TRACE("Version comparison..\n");
1923 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1924 version = msi_alloc(versize);
1925 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1927 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1929 sprintfW(filever,name_fmt,
1930 HIWORD(lpVer->dwFileVersionMS),
1931 LOWORD(lpVer->dwFileVersionMS),
1932 HIWORD(lpVer->dwFileVersionLS),
1933 LOWORD(lpVer->dwFileVersionLS));
1935 TRACE("new %s old %s\n", debugstr_w(file->Version),
1936 debugstr_w(filever));
1937 if (strcmpiW(filever,file->Version)<0)
1939 file->state = msifs_overwrite;
1940 /* FIXME: cost should be diff in size */
1941 comp->Cost += file->FileSize;
1943 else
1944 file->state = msifs_present;
1945 msi_free(version);
1947 else
1948 file->state = msifs_present;
1951 TRACE("Evaluating Condition Table\n");
1953 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1954 if (rc == ERROR_SUCCESS)
1956 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1957 package);
1958 msiobj_release(&view->hdr);
1961 TRACE("Enabling or Disabling Components\n");
1962 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1964 if (comp->Condition)
1966 if (MSI_EvaluateConditionW(package,
1967 comp->Condition) == MSICONDITION_FALSE)
1969 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1970 comp->Enabled = FALSE;
1975 MSI_SetPropertyW(package,szCosting,szOne);
1976 /* set default run level if not set */
1977 level = msi_dup_property( package, szlevel );
1978 if (!level)
1979 MSI_SetPropertyW(package,szlevel, szOne);
1980 msi_free(level);
1982 ACTION_UpdateInstallStates(package);
1984 return MSI_SetFeatureStates(package);
1987 /* OK this value is "interpreted" and then formatted based on the
1988 first few characters */
1989 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1990 DWORD *size)
1992 LPSTR data = NULL;
1993 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1995 if (value[1]=='x')
1997 LPWSTR ptr;
1998 CHAR byte[5];
1999 LPWSTR deformated = NULL;
2000 int count;
2002 deformat_string(package, &value[2], &deformated);
2004 /* binary value type */
2005 ptr = deformated;
2006 *type = REG_BINARY;
2007 if (strlenW(ptr)%2)
2008 *size = (strlenW(ptr)/2)+1;
2009 else
2010 *size = strlenW(ptr)/2;
2012 data = msi_alloc(*size);
2014 byte[0] = '0';
2015 byte[1] = 'x';
2016 byte[4] = 0;
2017 count = 0;
2018 /* if uneven pad with a zero in front */
2019 if (strlenW(ptr)%2)
2021 byte[2]= '0';
2022 byte[3]= *ptr;
2023 ptr++;
2024 data[count] = (BYTE)strtol(byte,NULL,0);
2025 count ++;
2026 TRACE("Uneven byte count\n");
2028 while (*ptr)
2030 byte[2]= *ptr;
2031 ptr++;
2032 byte[3]= *ptr;
2033 ptr++;
2034 data[count] = (BYTE)strtol(byte,NULL,0);
2035 count ++;
2037 msi_free(deformated);
2039 TRACE("Data %li bytes(%i)\n",*size,count);
2041 else
2043 LPWSTR deformated;
2044 LPWSTR p;
2045 DWORD d = 0;
2046 deformat_string(package, &value[1], &deformated);
2048 *type=REG_DWORD;
2049 *size = sizeof(DWORD);
2050 data = msi_alloc(*size);
2051 p = deformated;
2052 if (*p == '-')
2053 p++;
2054 while (*p)
2056 if ( (*p < '0') || (*p > '9') )
2057 break;
2058 d *= 10;
2059 d += (*p - '0');
2060 p++;
2062 if (deformated[0] == '-')
2063 d = -d;
2064 *(LPDWORD)data = d;
2065 TRACE("DWORD %li\n",*(LPDWORD)data);
2067 msi_free(deformated);
2070 else
2072 static const WCHAR szMulti[] = {'[','~',']',0};
2073 LPCWSTR ptr;
2074 *type=REG_SZ;
2076 if (value[0]=='#')
2078 if (value[1]=='%')
2080 ptr = &value[2];
2081 *type=REG_EXPAND_SZ;
2083 else
2084 ptr = &value[1];
2086 else
2087 ptr=value;
2089 if (strstrW(value,szMulti))
2090 *type = REG_MULTI_SZ;
2092 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2094 return data;
2097 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2099 MSIPACKAGE *package = (MSIPACKAGE*)param;
2100 static const WCHAR szHCR[] =
2101 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2102 'R','O','O','T','\\',0};
2103 static const WCHAR szHCU[] =
2104 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2105 'U','S','E','R','\\',0};
2106 static const WCHAR szHLM[] =
2107 {'H','K','E','Y','_','L','O','C','A','L','_',
2108 'M','A','C','H','I','N','E','\\',0};
2109 static const WCHAR szHU[] =
2110 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2112 LPSTR value_data = NULL;
2113 HKEY root_key, hkey;
2114 DWORD type,size;
2115 LPWSTR deformated;
2116 LPCWSTR szRoot, component, name, key, value;
2117 MSICOMPONENT *comp;
2118 MSIRECORD * uirow;
2119 LPWSTR uikey;
2120 INT root;
2121 BOOL check_first = FALSE;
2122 UINT rc;
2124 ui_progress(package,2,0,0,0);
2126 value = NULL;
2127 key = NULL;
2128 uikey = NULL;
2129 name = NULL;
2131 component = MSI_RecordGetString(row, 6);
2132 comp = get_loaded_component(package,component);
2133 if (!comp)
2134 return ERROR_SUCCESS;
2136 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2138 TRACE("Skipping write due to disabled component %s\n",
2139 debugstr_w(component));
2141 comp->Action = comp->Installed;
2143 return ERROR_SUCCESS;
2146 comp->Action = INSTALLSTATE_LOCAL;
2148 name = MSI_RecordGetString(row, 4);
2149 if( MSI_RecordIsNull(row,5) && name )
2151 /* null values can have special meanings */
2152 if (name[0]=='-' && name[1] == 0)
2153 return ERROR_SUCCESS;
2154 else if ((name[0]=='+' && name[1] == 0) ||
2155 (name[0] == '*' && name[1] == 0))
2156 name = NULL;
2157 check_first = TRUE;
2160 root = MSI_RecordGetInteger(row,2);
2161 key = MSI_RecordGetString(row, 3);
2163 /* get the root key */
2164 switch (root)
2166 case -1:
2168 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2169 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2170 if (all_users && all_users[0] == '1')
2172 root_key = HKEY_LOCAL_MACHINE;
2173 szRoot = szHLM;
2175 else
2177 root_key = HKEY_CURRENT_USER;
2178 szRoot = szHCU;
2180 msi_free(all_users);
2182 break;
2183 case 0: root_key = HKEY_CLASSES_ROOT;
2184 szRoot = szHCR;
2185 break;
2186 case 1: root_key = HKEY_CURRENT_USER;
2187 szRoot = szHCU;
2188 break;
2189 case 2: root_key = HKEY_LOCAL_MACHINE;
2190 szRoot = szHLM;
2191 break;
2192 case 3: root_key = HKEY_USERS;
2193 szRoot = szHU;
2194 break;
2195 default:
2196 ERR("Unknown root %i\n",root);
2197 root_key=NULL;
2198 szRoot = NULL;
2199 break;
2201 if (!root_key)
2202 return ERROR_SUCCESS;
2204 deformat_string(package, key , &deformated);
2205 size = strlenW(deformated) + strlenW(szRoot) + 1;
2206 uikey = msi_alloc(size*sizeof(WCHAR));
2207 strcpyW(uikey,szRoot);
2208 strcatW(uikey,deformated);
2210 if (RegCreateKeyW( root_key, deformated, &hkey))
2212 ERR("Could not create key %s\n",debugstr_w(deformated));
2213 msi_free(deformated);
2214 msi_free(uikey);
2215 return ERROR_SUCCESS;
2217 msi_free(deformated);
2219 value = MSI_RecordGetString(row,5);
2220 if (value)
2221 value_data = parse_value(package, value, &type, &size);
2222 else
2224 static const WCHAR szEmpty[] = {0};
2225 value_data = (LPSTR)strdupW(szEmpty);
2226 size = 0;
2227 type = REG_SZ;
2230 deformat_string(package, name, &deformated);
2232 /* get the double nulls to terminate SZ_MULTI */
2233 if (type == REG_MULTI_SZ)
2234 size +=sizeof(WCHAR);
2236 if (!check_first)
2238 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2239 debugstr_w(uikey));
2240 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2242 else
2244 DWORD sz = 0;
2245 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2246 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2248 TRACE("value %s of %s checked already exists\n",
2249 debugstr_w(deformated), debugstr_w(uikey));
2251 else
2253 TRACE("Checked and setting value %s of %s\n",
2254 debugstr_w(deformated), debugstr_w(uikey));
2255 if (deformated || size)
2256 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2259 RegCloseKey(hkey);
2261 uirow = MSI_CreateRecord(3);
2262 MSI_RecordSetStringW(uirow,2,deformated);
2263 MSI_RecordSetStringW(uirow,1,uikey);
2265 if (type == REG_SZ)
2266 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2267 else
2268 MSI_RecordSetStringW(uirow,3,value);
2270 ui_actiondata(package,szWriteRegistryValues,uirow);
2271 msiobj_release( &uirow->hdr );
2273 msi_free(value_data);
2274 msi_free(deformated);
2275 msi_free(uikey);
2277 return ERROR_SUCCESS;
2280 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2282 UINT rc;
2283 MSIQUERY * view;
2284 static const WCHAR ExecSeqQuery[] =
2285 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2286 '`','R','e','g','i','s','t','r','y','`',0 };
2288 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2289 if (rc != ERROR_SUCCESS)
2290 return ERROR_SUCCESS;
2292 /* increment progress bar each time action data is sent */
2293 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2295 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2297 msiobj_release(&view->hdr);
2298 return rc;
2301 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2303 package->script->CurrentlyScripting = TRUE;
2305 return ERROR_SUCCESS;
2309 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2311 MSICOMPONENT *comp;
2312 DWORD progress = 0;
2313 DWORD total = 0;
2314 static const WCHAR q1[]=
2315 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2316 '`','R','e','g','i','s','t','r','y','`',0};
2317 UINT rc;
2318 MSIQUERY * view;
2319 MSIFEATURE *feature;
2320 MSIFILE *file;
2322 TRACE("InstallValidate\n");
2324 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2325 if (rc == ERROR_SUCCESS)
2327 MSI_IterateRecords( view, &progress, NULL, package );
2328 msiobj_release( &view->hdr );
2329 total += progress * REG_PROGRESS_VALUE;
2332 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2333 total += COMPONENT_PROGRESS_VALUE;
2335 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2336 total += file->FileSize;
2338 ui_progress(package,0,total,0,0);
2340 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2342 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2343 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2344 feature->ActionRequest);
2347 return ERROR_SUCCESS;
2350 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2352 MSIPACKAGE* package = (MSIPACKAGE*)param;
2353 LPCWSTR cond = NULL;
2354 LPCWSTR message = NULL;
2355 static const WCHAR title[]=
2356 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2358 cond = MSI_RecordGetString(row,1);
2360 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2362 LPWSTR deformated;
2363 message = MSI_RecordGetString(row,2);
2364 deformat_string(package,message,&deformated);
2365 MessageBoxW(NULL,deformated,title,MB_OK);
2366 msi_free(deformated);
2367 return ERROR_FUNCTION_FAILED;
2370 return ERROR_SUCCESS;
2373 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2375 UINT rc;
2376 MSIQUERY * view = NULL;
2377 static const WCHAR ExecSeqQuery[] =
2378 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2379 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2381 TRACE("Checking launch conditions\n");
2383 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2384 if (rc != ERROR_SUCCESS)
2385 return ERROR_SUCCESS;
2387 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2388 msiobj_release(&view->hdr);
2390 return rc;
2393 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2396 if (!cmp->KeyPath)
2397 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2399 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2401 MSIRECORD * row = 0;
2402 UINT root,len;
2403 LPWSTR deformated,buffer,deformated_name;
2404 LPCWSTR key,name;
2405 static const WCHAR ExecSeqQuery[] =
2406 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2407 '`','R','e','g','i','s','t','r','y','`',' ',
2408 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2409 ' ','=',' ' ,'\'','%','s','\'',0 };
2410 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2411 static const WCHAR fmt2[]=
2412 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2414 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2415 if (!row)
2416 return NULL;
2418 root = MSI_RecordGetInteger(row,2);
2419 key = MSI_RecordGetString(row, 3);
2420 name = MSI_RecordGetString(row, 4);
2421 deformat_string(package, key , &deformated);
2422 deformat_string(package, name, &deformated_name);
2424 len = strlenW(deformated) + 6;
2425 if (deformated_name)
2426 len+=strlenW(deformated_name);
2428 buffer = msi_alloc( len *sizeof(WCHAR));
2430 if (deformated_name)
2431 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2432 else
2433 sprintfW(buffer,fmt,root,deformated);
2435 msi_free(deformated);
2436 msi_free(deformated_name);
2437 msiobj_release(&row->hdr);
2439 return buffer;
2441 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2443 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2444 return NULL;
2446 else
2448 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2450 if (file)
2451 return strdupW( file->TargetPath );
2453 return NULL;
2456 static HKEY openSharedDLLsKey(void)
2458 HKEY hkey=0;
2459 static const WCHAR path[] =
2460 {'S','o','f','t','w','a','r','e','\\',
2461 'M','i','c','r','o','s','o','f','t','\\',
2462 'W','i','n','d','o','w','s','\\',
2463 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2464 'S','h','a','r','e','d','D','L','L','s',0};
2466 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2467 return hkey;
2470 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2472 HKEY hkey;
2473 DWORD count=0;
2474 DWORD type;
2475 DWORD sz = sizeof(count);
2476 DWORD rc;
2478 hkey = openSharedDLLsKey();
2479 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2480 if (rc != ERROR_SUCCESS)
2481 count = 0;
2482 RegCloseKey(hkey);
2483 return count;
2486 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2488 HKEY hkey;
2490 hkey = openSharedDLLsKey();
2491 if (count > 0)
2492 msi_reg_set_val_dword( hkey, path, count );
2493 else
2494 RegDeleteValueW(hkey,path);
2495 RegCloseKey(hkey);
2496 return count;
2500 * Return TRUE if the count should be written out and FALSE if not
2502 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2504 MSIFEATURE *feature;
2505 INT count = 0;
2506 BOOL write = FALSE;
2508 /* only refcount DLLs */
2509 if (comp->KeyPath == NULL ||
2510 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2511 comp->Attributes & msidbComponentAttributesODBCDataSource)
2512 write = FALSE;
2513 else
2515 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2516 write = (count > 0);
2518 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2519 write = TRUE;
2522 /* increment counts */
2523 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2525 ComponentList *cl;
2527 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2528 continue;
2530 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2532 if ( cl->component == comp )
2533 count++;
2537 /* decrement counts */
2538 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2540 ComponentList *cl;
2542 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2543 continue;
2545 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2547 if ( cl->component == comp )
2548 count--;
2552 /* ref count all the files in the component */
2553 if (write)
2555 MSIFILE *file;
2557 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2559 if (file->Component == comp)
2560 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2564 /* add a count for permenent */
2565 if (comp->Attributes & msidbComponentAttributesPermanent)
2566 count ++;
2568 comp->RefCount = count;
2570 if (write)
2571 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2575 * Ok further analysis makes me think that this work is
2576 * actually done in the PublishComponents and PublishFeatures
2577 * step, and not here. It appears like the keypath and all that is
2578 * resolved in this step, however actually written in the Publish steps.
2579 * But we will leave it here for now because it is unclear
2581 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2583 WCHAR squished_pc[GUID_SIZE];
2584 WCHAR squished_cc[GUID_SIZE];
2585 UINT rc;
2586 MSICOMPONENT *comp;
2587 HKEY hkey=0,hkey2=0;
2589 /* writes the Component and Features values to the registry */
2591 rc = MSIREG_OpenComponents(&hkey);
2592 if (rc != ERROR_SUCCESS)
2593 return rc;
2595 squash_guid(package->ProductCode,squished_pc);
2596 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2598 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2600 MSIRECORD * uirow;
2602 ui_progress(package,2,0,0,0);
2603 if (!comp->ComponentId)
2604 continue;
2606 squash_guid(comp->ComponentId,squished_cc);
2608 msi_free(comp->FullKeypath);
2609 comp->FullKeypath = resolve_keypath( package, comp );
2611 /* do the refcounting */
2612 ACTION_RefCountComponent( package, comp );
2614 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2615 debugstr_w(comp->Component),
2616 debugstr_w(squished_cc),
2617 debugstr_w(comp->FullKeypath),
2618 comp->RefCount);
2620 * Write the keypath out if the component is to be registered
2621 * and delete the key if the component is to be deregistered
2623 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2625 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2626 if (rc != ERROR_SUCCESS)
2627 continue;
2629 if (!comp->FullKeypath)
2630 continue;
2632 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2634 if (comp->Attributes & msidbComponentAttributesPermanent)
2636 static const WCHAR szPermKey[] =
2637 { '0','0','0','0','0','0','0','0','0','0','0','0',
2638 '0','0','0','0','0','0','0','0','0','0','0','0',
2639 '0','0','0','0','0','0','0','0',0 };
2641 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2644 RegCloseKey(hkey2);
2646 /* UI stuff */
2647 uirow = MSI_CreateRecord(3);
2648 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2649 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2650 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2651 ui_actiondata(package,szProcessComponents,uirow);
2652 msiobj_release( &uirow->hdr );
2654 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2656 DWORD res;
2658 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2659 if (rc != ERROR_SUCCESS)
2660 continue;
2662 RegDeleteValueW(hkey2,squished_pc);
2664 /* if the key is empty delete it */
2665 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2666 RegCloseKey(hkey2);
2667 if (res == ERROR_NO_MORE_ITEMS)
2668 RegDeleteKeyW(hkey,squished_cc);
2670 /* UI stuff */
2671 uirow = MSI_CreateRecord(2);
2672 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2673 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2674 ui_actiondata(package,szProcessComponents,uirow);
2675 msiobj_release( &uirow->hdr );
2678 RegCloseKey(hkey);
2679 return rc;
2682 typedef struct {
2683 CLSID clsid;
2684 LPWSTR source;
2686 LPWSTR path;
2687 ITypeLib *ptLib;
2688 } typelib_struct;
2690 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2691 LPWSTR lpszName, LONG_PTR lParam)
2693 TLIBATTR *attr;
2694 typelib_struct *tl_struct = (typelib_struct*) lParam;
2695 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2696 int sz;
2697 HRESULT res;
2699 if (!IS_INTRESOURCE(lpszName))
2701 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2702 return TRUE;
2705 sz = strlenW(tl_struct->source)+4;
2706 sz *= sizeof(WCHAR);
2708 if ((INT_PTR)lpszName == 1)
2709 tl_struct->path = strdupW(tl_struct->source);
2710 else
2712 tl_struct->path = msi_alloc(sz);
2713 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2716 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2717 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2718 if (!SUCCEEDED(res))
2720 msi_free(tl_struct->path);
2721 tl_struct->path = NULL;
2723 return TRUE;
2726 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2727 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2729 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2730 return FALSE;
2733 msi_free(tl_struct->path);
2734 tl_struct->path = NULL;
2736 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2737 ITypeLib_Release(tl_struct->ptLib);
2739 return TRUE;
2742 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2744 MSIPACKAGE* package = (MSIPACKAGE*)param;
2745 LPCWSTR component;
2746 MSICOMPONENT *comp;
2747 MSIFILE *file;
2748 typelib_struct tl_struct;
2749 HMODULE module;
2750 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2752 component = MSI_RecordGetString(row,3);
2753 comp = get_loaded_component(package,component);
2754 if (!comp)
2755 return ERROR_SUCCESS;
2757 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2759 TRACE("Skipping typelib reg due to disabled component\n");
2761 comp->Action = comp->Installed;
2763 return ERROR_SUCCESS;
2766 comp->Action = INSTALLSTATE_LOCAL;
2768 file = get_loaded_file( package, comp->KeyPath );
2769 if (!file)
2770 return ERROR_SUCCESS;
2772 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2773 if (module)
2775 LPCWSTR guid;
2776 guid = MSI_RecordGetString(row,1);
2777 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2778 tl_struct.source = strdupW( file->TargetPath );
2779 tl_struct.path = NULL;
2781 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2782 (LONG_PTR)&tl_struct);
2784 if (tl_struct.path)
2786 LPWSTR help = NULL;
2787 LPCWSTR helpid;
2788 HRESULT res;
2790 helpid = MSI_RecordGetString(row,6);
2792 if (helpid)
2793 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2794 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2795 msi_free(help);
2797 if (!SUCCEEDED(res))
2798 ERR("Failed to register type library %s\n",
2799 debugstr_w(tl_struct.path));
2800 else
2802 ui_actiondata(package,szRegisterTypeLibraries,row);
2804 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2807 ITypeLib_Release(tl_struct.ptLib);
2808 msi_free(tl_struct.path);
2810 else
2811 ERR("Failed to load type library %s\n",
2812 debugstr_w(tl_struct.source));
2814 FreeLibrary(module);
2815 msi_free(tl_struct.source);
2817 else
2818 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2820 return ERROR_SUCCESS;
2823 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2826 * OK this is a bit confusing.. I am given a _Component key and I believe
2827 * that the file that is being registered as a type library is the "key file
2828 * of that component" which I interpret to mean "The file in the KeyPath of
2829 * that component".
2831 UINT rc;
2832 MSIQUERY * view;
2833 static const WCHAR Query[] =
2834 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2835 '`','T','y','p','e','L','i','b','`',0};
2837 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2838 if (rc != ERROR_SUCCESS)
2839 return ERROR_SUCCESS;
2841 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2842 msiobj_release(&view->hdr);
2843 return rc;
2846 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2848 MSIPACKAGE *package = (MSIPACKAGE*)param;
2849 LPWSTR target_file, target_folder, filename;
2850 LPCWSTR buffer, extension;
2851 MSICOMPONENT *comp;
2852 static const WCHAR szlnk[]={'.','l','n','k',0};
2853 IShellLinkW *sl = NULL;
2854 IPersistFile *pf = NULL;
2855 HRESULT res;
2857 buffer = MSI_RecordGetString(row,4);
2858 comp = get_loaded_component(package,buffer);
2859 if (!comp)
2860 return ERROR_SUCCESS;
2862 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2864 TRACE("Skipping shortcut creation due to disabled component\n");
2866 comp->Action = comp->Installed;
2868 return ERROR_SUCCESS;
2871 comp->Action = INSTALLSTATE_LOCAL;
2873 ui_actiondata(package,szCreateShortcuts,row);
2875 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2876 &IID_IShellLinkW, (LPVOID *) &sl );
2878 if (FAILED( res ))
2880 ERR("CLSID_ShellLink not available\n");
2881 goto err;
2884 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2885 if (FAILED( res ))
2887 ERR("QueryInterface(IID_IPersistFile) failed\n");
2888 goto err;
2891 buffer = MSI_RecordGetString(row,2);
2892 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2894 /* may be needed because of a bug somehwere else */
2895 create_full_pathW(target_folder);
2897 filename = msi_dup_record_field( row, 3 );
2898 reduce_to_longfilename(filename);
2900 extension = strchrW(filename,'.');
2901 if (!extension || strcmpiW(extension,szlnk))
2903 int len = strlenW(filename);
2904 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2905 memcpy(filename + len, szlnk, sizeof(szlnk));
2907 target_file = build_directory_name(2, target_folder, filename);
2908 msi_free(target_folder);
2909 msi_free(filename);
2911 buffer = MSI_RecordGetString(row,5);
2912 if (strchrW(buffer,'['))
2914 LPWSTR deformated;
2915 deformat_string(package,buffer,&deformated);
2916 IShellLinkW_SetPath(sl,deformated);
2917 msi_free(deformated);
2919 else
2921 FIXME("poorly handled shortcut format, advertised shortcut\n");
2922 IShellLinkW_SetPath(sl,comp->FullKeypath);
2925 if (!MSI_RecordIsNull(row,6))
2927 LPWSTR deformated;
2928 buffer = MSI_RecordGetString(row,6);
2929 deformat_string(package,buffer,&deformated);
2930 IShellLinkW_SetArguments(sl,deformated);
2931 msi_free(deformated);
2934 if (!MSI_RecordIsNull(row,7))
2936 buffer = MSI_RecordGetString(row,7);
2937 IShellLinkW_SetDescription(sl,buffer);
2940 if (!MSI_RecordIsNull(row,8))
2941 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2943 if (!MSI_RecordIsNull(row,9))
2945 LPWSTR Path;
2946 INT index;
2948 buffer = MSI_RecordGetString(row,9);
2950 Path = build_icon_path(package,buffer);
2951 index = MSI_RecordGetInteger(row,10);
2953 /* no value means 0 */
2954 if (index == MSI_NULL_INTEGER)
2955 index = 0;
2957 IShellLinkW_SetIconLocation(sl,Path,index);
2958 msi_free(Path);
2961 if (!MSI_RecordIsNull(row,11))
2962 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2964 if (!MSI_RecordIsNull(row,12))
2966 LPWSTR Path;
2967 buffer = MSI_RecordGetString(row,12);
2968 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2969 if (Path)
2970 IShellLinkW_SetWorkingDirectory(sl,Path);
2971 msi_free(Path);
2974 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2975 IPersistFile_Save(pf,target_file,FALSE);
2977 msi_free(target_file);
2979 err:
2980 if (pf)
2981 IPersistFile_Release( pf );
2982 if (sl)
2983 IShellLinkW_Release( sl );
2985 return ERROR_SUCCESS;
2988 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2990 UINT rc;
2991 HRESULT res;
2992 MSIQUERY * view;
2993 static const WCHAR Query[] =
2994 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2995 '`','S','h','o','r','t','c','u','t','`',0};
2997 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2998 if (rc != ERROR_SUCCESS)
2999 return ERROR_SUCCESS;
3001 res = CoInitialize( NULL );
3002 if (FAILED (res))
3004 ERR("CoInitialize failed\n");
3005 return ERROR_FUNCTION_FAILED;
3008 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3009 msiobj_release(&view->hdr);
3011 CoUninitialize();
3013 return rc;
3016 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3018 MSIPACKAGE* package = (MSIPACKAGE*)param;
3019 HANDLE the_file;
3020 LPWSTR FilePath;
3021 LPCWSTR FileName;
3022 CHAR buffer[1024];
3023 DWORD sz;
3024 UINT rc;
3025 MSIRECORD *uirow;
3027 FileName = MSI_RecordGetString(row,1);
3028 if (!FileName)
3030 ERR("Unable to get FileName\n");
3031 return ERROR_SUCCESS;
3034 FilePath = build_icon_path(package,FileName);
3036 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3038 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3039 FILE_ATTRIBUTE_NORMAL, NULL);
3041 if (the_file == INVALID_HANDLE_VALUE)
3043 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3044 msi_free(FilePath);
3045 return ERROR_SUCCESS;
3050 DWORD write;
3051 sz = 1024;
3052 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3053 if (rc != ERROR_SUCCESS)
3055 ERR("Failed to get stream\n");
3056 CloseHandle(the_file);
3057 DeleteFileW(FilePath);
3058 break;
3060 WriteFile(the_file,buffer,sz,&write,NULL);
3061 } while (sz == 1024);
3063 msi_free(FilePath);
3065 CloseHandle(the_file);
3067 uirow = MSI_CreateRecord(1);
3068 MSI_RecordSetStringW(uirow,1,FileName);
3069 ui_actiondata(package,szPublishProduct,uirow);
3070 msiobj_release( &uirow->hdr );
3072 return ERROR_SUCCESS;
3076 * 99% of the work done here is only done for
3077 * advertised installs. However this is where the
3078 * Icon table is processed and written out
3079 * so that is what I am going to do here.
3081 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3083 UINT rc;
3084 MSIQUERY * view;
3085 static const WCHAR Query[]=
3086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3087 '`','I','c','o','n','`',0};
3088 /* for registry stuff */
3089 HKEY hkey=0;
3090 HKEY hukey=0;
3091 static const WCHAR szProductLanguage[] =
3092 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3093 static const WCHAR szARPProductIcon[] =
3094 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3095 static const WCHAR szProductVersion[] =
3096 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3097 DWORD langid;
3098 LPWSTR buffer;
3099 DWORD size;
3100 MSIHANDLE hDb, hSumInfo;
3102 /* write out icon files */
3104 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3105 if (rc == ERROR_SUCCESS)
3107 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3108 msiobj_release(&view->hdr);
3111 /* ok there is a lot more done here but i need to figure out what */
3113 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3114 if (rc != ERROR_SUCCESS)
3115 goto end;
3117 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3118 if (rc != ERROR_SUCCESS)
3119 goto end;
3122 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3123 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3124 msi_free(buffer);
3126 langid = msi_get_property_int( package, szProductLanguage, 0 );
3127 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3129 buffer = msi_dup_property( package, szARPProductIcon );
3130 if (buffer)
3132 LPWSTR path = build_icon_path(package,buffer);
3133 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3134 msi_free( path );
3136 msi_free(buffer);
3138 buffer = msi_dup_property( package, szProductVersion );
3139 if (buffer)
3141 DWORD verdword = msi_version_str_to_dword(buffer);
3142 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3144 msi_free(buffer);
3146 /* FIXME: Need to write more keys to the user registry */
3148 hDb= alloc_msihandle( &package->db->hdr );
3149 if (!hDb) {
3150 rc = ERROR_NOT_ENOUGH_MEMORY;
3151 goto end;
3153 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3154 MsiCloseHandle(hDb);
3155 if (rc == ERROR_SUCCESS)
3157 WCHAR guidbuffer[0x200];
3158 size = 0x200;
3159 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3160 guidbuffer, &size);
3161 if (rc == ERROR_SUCCESS)
3163 WCHAR squashed[GUID_SIZE];
3164 /* for now we only care about the first guid */
3165 LPWSTR ptr = strchrW(guidbuffer,';');
3166 if (ptr) *ptr = 0;
3167 squash_guid(guidbuffer,squashed);
3168 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3170 else
3172 ERR("Unable to query Revision_Number...\n");
3173 rc = ERROR_SUCCESS;
3175 MsiCloseHandle(hSumInfo);
3177 else
3179 ERR("Unable to open Summary Information\n");
3180 rc = ERROR_SUCCESS;
3183 end:
3185 RegCloseKey(hkey);
3186 RegCloseKey(hukey);
3188 return rc;
3191 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3193 MSIPACKAGE *package = (MSIPACKAGE*)param;
3194 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3195 LPWSTR deformated_section, deformated_key, deformated_value;
3196 LPWSTR folder, fullname = NULL;
3197 MSIRECORD * uirow;
3198 INT action;
3199 MSICOMPONENT *comp;
3200 static const WCHAR szWindowsFolder[] =
3201 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3203 component = MSI_RecordGetString(row, 8);
3204 comp = get_loaded_component(package,component);
3206 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3208 TRACE("Skipping ini file due to disabled component %s\n",
3209 debugstr_w(component));
3211 comp->Action = comp->Installed;
3213 return ERROR_SUCCESS;
3216 comp->Action = INSTALLSTATE_LOCAL;
3218 identifier = MSI_RecordGetString(row,1);
3219 filename = MSI_RecordGetString(row,2);
3220 dirproperty = MSI_RecordGetString(row,3);
3221 section = MSI_RecordGetString(row,4);
3222 key = MSI_RecordGetString(row,5);
3223 value = MSI_RecordGetString(row,6);
3224 action = MSI_RecordGetInteger(row,7);
3226 deformat_string(package,section,&deformated_section);
3227 deformat_string(package,key,&deformated_key);
3228 deformat_string(package,value,&deformated_value);
3230 if (dirproperty)
3232 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3233 if (!folder)
3234 folder = msi_dup_property( package, dirproperty );
3236 else
3237 folder = msi_dup_property( package, szWindowsFolder );
3239 if (!folder)
3241 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3242 goto cleanup;
3245 fullname = build_directory_name(2, folder, filename);
3247 if (action == 0)
3249 TRACE("Adding value %s to section %s in %s\n",
3250 debugstr_w(deformated_key), debugstr_w(deformated_section),
3251 debugstr_w(fullname));
3252 WritePrivateProfileStringW(deformated_section, deformated_key,
3253 deformated_value, fullname);
3255 else if (action == 1)
3257 WCHAR returned[10];
3258 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3259 returned, 10, fullname);
3260 if (returned[0] == 0)
3262 TRACE("Adding value %s to section %s in %s\n",
3263 debugstr_w(deformated_key), debugstr_w(deformated_section),
3264 debugstr_w(fullname));
3266 WritePrivateProfileStringW(deformated_section, deformated_key,
3267 deformated_value, fullname);
3270 else if (action == 3)
3271 FIXME("Append to existing section not yet implemented\n");
3273 uirow = MSI_CreateRecord(4);
3274 MSI_RecordSetStringW(uirow,1,identifier);
3275 MSI_RecordSetStringW(uirow,2,deformated_section);
3276 MSI_RecordSetStringW(uirow,3,deformated_key);
3277 MSI_RecordSetStringW(uirow,4,deformated_value);
3278 ui_actiondata(package,szWriteIniValues,uirow);
3279 msiobj_release( &uirow->hdr );
3280 cleanup:
3281 msi_free(fullname);
3282 msi_free(folder);
3283 msi_free(deformated_key);
3284 msi_free(deformated_value);
3285 msi_free(deformated_section);
3286 return ERROR_SUCCESS;
3289 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3291 UINT rc;
3292 MSIQUERY * view;
3293 static const WCHAR ExecSeqQuery[] =
3294 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3295 '`','I','n','i','F','i','l','e','`',0};
3297 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3298 if (rc != ERROR_SUCCESS)
3300 TRACE("no IniFile table\n");
3301 return ERROR_SUCCESS;
3304 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3305 msiobj_release(&view->hdr);
3306 return rc;
3309 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3311 MSIPACKAGE *package = (MSIPACKAGE*)param;
3312 LPCWSTR filename;
3313 LPWSTR FullName;
3314 MSIFILE *file;
3315 DWORD len;
3316 static const WCHAR ExeStr[] =
3317 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3318 static const WCHAR close[] = {'\"',0};
3319 STARTUPINFOW si;
3320 PROCESS_INFORMATION info;
3321 BOOL brc;
3322 MSIRECORD *uirow;
3323 LPWSTR uipath, p;
3325 memset(&si,0,sizeof(STARTUPINFOW));
3327 filename = MSI_RecordGetString(row,1);
3328 file = get_loaded_file( package, filename );
3330 if (!file)
3332 ERR("Unable to find file id %s\n",debugstr_w(filename));
3333 return ERROR_SUCCESS;
3336 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3338 FullName = msi_alloc(len*sizeof(WCHAR));
3339 strcpyW(FullName,ExeStr);
3340 strcatW( FullName, file->TargetPath );
3341 strcatW(FullName,close);
3343 TRACE("Registering %s\n",debugstr_w(FullName));
3344 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3345 &si, &info);
3347 if (brc)
3348 msi_dialog_check_messages(info.hProcess);
3350 msi_free(FullName);
3352 /* the UI chunk */
3353 uirow = MSI_CreateRecord( 2 );
3354 uipath = strdupW( file->TargetPath );
3355 p = strrchrW(uipath,'\\');
3356 if (p)
3357 p[1]=0;
3358 MSI_RecordSetStringW( uirow, 1, &p[2] );
3359 MSI_RecordSetStringW( uirow, 2, uipath);
3360 ui_actiondata( package, szSelfRegModules, uirow);
3361 msiobj_release( &uirow->hdr );
3362 msi_free( uipath );
3363 /* FIXME: call ui_progress? */
3365 return ERROR_SUCCESS;
3368 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3370 UINT rc;
3371 MSIQUERY * view;
3372 static const WCHAR ExecSeqQuery[] =
3373 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3374 '`','S','e','l','f','R','e','g','`',0};
3376 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3377 if (rc != ERROR_SUCCESS)
3379 TRACE("no SelfReg table\n");
3380 return ERROR_SUCCESS;
3383 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3384 msiobj_release(&view->hdr);
3386 return ERROR_SUCCESS;
3389 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3391 MSIFEATURE *feature;
3392 UINT rc;
3393 HKEY hkey=0;
3394 HKEY hukey=0;
3396 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3397 if (rc != ERROR_SUCCESS)
3398 goto end;
3400 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3401 if (rc != ERROR_SUCCESS)
3402 goto end;
3404 /* here the guids are base 85 encoded */
3405 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3407 ComponentList *cl;
3408 LPWSTR data = NULL;
3409 GUID clsid;
3410 INT size;
3411 BOOL absent = FALSE;
3412 MSIRECORD *uirow;
3414 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3415 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3416 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3417 absent = TRUE;
3419 size = 1;
3420 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3422 size += 21;
3424 if (feature->Feature_Parent)
3425 size += strlenW( feature->Feature_Parent )+2;
3427 data = msi_alloc(size * sizeof(WCHAR));
3429 data[0] = 0;
3430 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3432 MSICOMPONENT* component = cl->component;
3433 WCHAR buf[21];
3435 buf[0] = 0;
3436 if (component->ComponentId)
3438 TRACE("From %s\n",debugstr_w(component->ComponentId));
3439 CLSIDFromString(component->ComponentId, &clsid);
3440 encode_base85_guid(&clsid,buf);
3441 TRACE("to %s\n",debugstr_w(buf));
3442 strcatW(data,buf);
3445 if (feature->Feature_Parent)
3447 static const WCHAR sep[] = {'\2',0};
3448 strcatW(data,sep);
3449 strcatW(data,feature->Feature_Parent);
3452 msi_reg_set_val_str( hkey, feature->Feature, data );
3453 msi_free(data);
3455 size = 0;
3456 if (feature->Feature_Parent)
3457 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3458 if (!absent)
3460 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3461 (LPBYTE)feature->Feature_Parent,size);
3463 else
3465 size += 2*sizeof(WCHAR);
3466 data = msi_alloc(size);
3467 data[0] = 0x6;
3468 data[1] = 0;
3469 if (feature->Feature_Parent)
3470 strcpyW( &data[1], feature->Feature_Parent );
3471 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3472 (LPBYTE)data,size);
3473 msi_free(data);
3476 /* the UI chunk */
3477 uirow = MSI_CreateRecord( 1 );
3478 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3479 ui_actiondata( package, szPublishFeatures, uirow);
3480 msiobj_release( &uirow->hdr );
3481 /* FIXME: call ui_progress? */
3484 end:
3485 RegCloseKey(hkey);
3486 RegCloseKey(hukey);
3487 return rc;
3490 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3492 static const WCHAR installerPathFmt[] = {
3493 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3494 static const WCHAR fmt[] = {
3495 '%','s','\\',
3496 'I','n','s','t','a','l','l','e','r','\\',
3497 '%','x','.','m','s','i',0};
3498 static const WCHAR szOriginalDatabase[] =
3499 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3500 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3501 INT num, start;
3502 LPWSTR msiFilePath;
3503 BOOL r;
3505 /* copy the package locally */
3506 num = GetTickCount() & 0xffff;
3507 if (!num)
3508 num = 1;
3509 start = num;
3510 GetWindowsDirectoryW( windir, MAX_PATH );
3511 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3514 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3515 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3516 if (handle != INVALID_HANDLE_VALUE)
3518 CloseHandle(handle);
3519 break;
3521 if (GetLastError() != ERROR_FILE_EXISTS &&
3522 GetLastError() != ERROR_SHARING_VIOLATION)
3523 break;
3524 if (!(++num & 0xffff)) num = 1;
3525 sprintfW(packagefile,fmt,num);
3526 } while (num != start);
3528 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3529 create_full_pathW(path);
3531 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3533 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3534 r = CopyFileW( msiFilePath, packagefile, FALSE);
3535 msi_free( msiFilePath );
3537 if (!r)
3539 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3540 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3541 return ERROR_FUNCTION_FAILED;
3544 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3545 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3546 return ERROR_SUCCESS;
3549 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3551 LPWSTR prop, val, key;
3552 static const LPCSTR propval[] = {
3553 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3554 "ARPCONTACT", "Contact",
3555 "ARPCOMMENTS", "Comments",
3556 "ProductName", "DisplayName",
3557 "ProductVersion", "DisplayVersion",
3558 "ARPHELPLINK", "HelpLink",
3559 "ARPHELPTELEPHONE", "HelpTelephone",
3560 "ARPINSTALLLOCATION", "InstallLocation",
3561 "SourceDir", "InstallSource",
3562 "Manufacturer", "Publisher",
3563 "ARPREADME", "Readme",
3564 "ARPSIZE", "Size",
3565 "ARPURLINFOABOUT", "URLInfoAbout",
3566 "ARPURLUPDATEINFO", "URLUpdateInfo",
3567 NULL,
3569 const LPCSTR *p = propval;
3571 while( *p )
3573 prop = strdupAtoW( *p++ );
3574 key = strdupAtoW( *p++ );
3575 val = msi_dup_property( package, prop );
3576 msi_reg_set_val_str( hkey, key, val );
3577 msi_free(val);
3578 msi_free(key);
3579 msi_free(prop);
3581 return ERROR_SUCCESS;
3584 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3586 HKEY hkey=0;
3587 LPWSTR buffer = NULL;
3588 UINT rc;
3589 DWORD size, langid;
3590 static const WCHAR szWindowsInstaller[] =
3591 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3592 static const WCHAR szUpgradeCode[] =
3593 {'U','p','g','r','a','d','e','C','o','d','e',0};
3594 static const WCHAR modpath_fmt[] =
3595 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3596 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3597 static const WCHAR szModifyPath[] =
3598 {'M','o','d','i','f','y','P','a','t','h',0};
3599 static const WCHAR szUninstallString[] =
3600 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3601 static const WCHAR szEstimatedSize[] =
3602 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3603 static const WCHAR szProductLanguage[] =
3604 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3605 static const WCHAR szProductVersion[] =
3606 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3608 SYSTEMTIME systime;
3609 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3610 LPWSTR upgrade_code;
3611 WCHAR szDate[9];
3613 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3614 if (rc != ERROR_SUCCESS)
3615 return rc;
3617 /* dump all the info i can grab */
3618 /* FIXME: Flesh out more information */
3620 msi_write_uninstall_property_vals( package, hkey );
3622 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3624 msi_make_package_local( package, hkey );
3626 /* do ModifyPath and UninstallString */
3627 size = deformat_string(package,modpath_fmt,&buffer);
3628 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3629 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3630 msi_free(buffer);
3632 /* FIXME: Write real Estimated Size when we have it */
3633 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3635 GetLocalTime(&systime);
3636 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3637 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3639 langid = msi_get_property_int( package, szProductLanguage, 0 );
3640 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3642 buffer = msi_dup_property( package, szProductVersion );
3643 if (buffer)
3645 DWORD verdword = msi_version_str_to_dword(buffer);
3647 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3648 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3649 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3651 msi_free(buffer);
3653 /* Handle Upgrade Codes */
3654 upgrade_code = msi_dup_property( package, szUpgradeCode );
3655 if (upgrade_code)
3657 HKEY hkey2;
3658 WCHAR squashed[33];
3659 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3660 squash_guid(package->ProductCode,squashed);
3661 msi_reg_set_val_str( hkey2, squashed, NULL );
3662 RegCloseKey(hkey2);
3663 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3664 squash_guid(package->ProductCode,squashed);
3665 msi_reg_set_val_str( hkey2, squashed, NULL );
3666 RegCloseKey(hkey2);
3668 msi_free(upgrade_code);
3671 RegCloseKey(hkey);
3673 /* FIXME: call ui_actiondata */
3675 return ERROR_SUCCESS;
3678 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3680 return execute_script(package,INSTALL_SCRIPT);
3683 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3685 UINT rc;
3687 /* turn off scheduleing */
3688 package->script->CurrentlyScripting= FALSE;
3690 /* first do the same as an InstallExecute */
3691 rc = ACTION_InstallExecute(package);
3692 if (rc != ERROR_SUCCESS)
3693 return rc;
3695 /* then handle Commit Actions */
3696 rc = execute_script(package,COMMIT_SCRIPT);
3698 return rc;
3701 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3703 static const WCHAR RunOnce[] = {
3704 'S','o','f','t','w','a','r','e','\\',
3705 'M','i','c','r','o','s','o','f','t','\\',
3706 'W','i','n','d','o','w','s','\\',
3707 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3708 'R','u','n','O','n','c','e',0};
3709 static const WCHAR InstallRunOnce[] = {
3710 'S','o','f','t','w','a','r','e','\\',
3711 'M','i','c','r','o','s','o','f','t','\\',
3712 'W','i','n','d','o','w','s','\\',
3713 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3714 'I','n','s','t','a','l','l','e','r','\\',
3715 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3717 static const WCHAR msiexec_fmt[] = {
3718 '%','s',
3719 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3720 '\"','%','s','\"',0};
3721 static const WCHAR install_fmt[] = {
3722 '/','I',' ','\"','%','s','\"',' ',
3723 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3724 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3725 WCHAR buffer[256], sysdir[MAX_PATH];
3726 HKEY hkey;
3727 WCHAR squished_pc[100];
3729 squash_guid(package->ProductCode,squished_pc);
3731 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3732 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3733 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3734 squished_pc);
3736 msi_reg_set_val_str( hkey, squished_pc, buffer );
3737 RegCloseKey(hkey);
3739 TRACE("Reboot command %s\n",debugstr_w(buffer));
3741 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3742 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3744 msi_reg_set_val_str( hkey, squished_pc, buffer );
3745 RegCloseKey(hkey);
3747 return ERROR_INSTALL_SUSPEND;
3750 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3752 DWORD attrib;
3753 UINT rc;
3755 * we are currently doing what should be done here in the top level Install
3756 * however for Adminastrative and uninstalls this step will be needed
3758 if (!package->PackagePath)
3759 return ERROR_SUCCESS;
3761 attrib = GetFileAttributesW(package->PackagePath);
3762 if (attrib == INVALID_FILE_ATTRIBUTES)
3764 LPWSTR prompt;
3765 LPWSTR msg;
3766 DWORD size = 0;
3768 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3769 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3770 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3771 if (rc == ERROR_MORE_DATA)
3773 prompt = msi_alloc(size * sizeof(WCHAR));
3774 MsiSourceListGetInfoW(package->ProductCode, NULL,
3775 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3776 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3778 else
3779 prompt = strdupW(package->PackagePath);
3781 msg = generate_error_string(package,1302,1,prompt);
3782 while(attrib == INVALID_FILE_ATTRIBUTES)
3784 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3785 if (rc == IDCANCEL)
3787 rc = ERROR_INSTALL_USEREXIT;
3788 break;
3790 attrib = GetFileAttributesW(package->PackagePath);
3792 msi_free(prompt);
3793 rc = ERROR_SUCCESS;
3795 else
3796 return ERROR_SUCCESS;
3798 return rc;
3801 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3803 HKEY hkey=0;
3804 LPWSTR buffer;
3805 LPWSTR productid;
3806 UINT rc,i;
3808 static const WCHAR szPropKeys[][80] =
3810 {'P','r','o','d','u','c','t','I','D',0},
3811 {'U','S','E','R','N','A','M','E',0},
3812 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3813 {0},
3816 static const WCHAR szRegKeys[][80] =
3818 {'P','r','o','d','u','c','t','I','D',0},
3819 {'R','e','g','O','w','n','e','r',0},
3820 {'R','e','g','C','o','m','p','a','n','y',0},
3821 {0},
3824 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3825 if (!productid)
3826 return ERROR_SUCCESS;
3828 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3829 if (rc != ERROR_SUCCESS)
3830 goto end;
3832 for( i = 0; szPropKeys[i][0]; i++ )
3834 buffer = msi_dup_property( package, szPropKeys[i] );
3835 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3836 msi_free( buffer );
3839 end:
3840 msi_free(productid);
3841 RegCloseKey(hkey);
3843 /* FIXME: call ui_actiondata */
3845 return ERROR_SUCCESS;
3849 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3851 UINT rc;
3853 package->script->InWhatSequence |= SEQUENCE_EXEC;
3854 rc = ACTION_ProcessExecSequence(package,FALSE);
3855 return rc;
3860 * Code based off of code located here
3861 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3863 * Using string index 4 (full font name) instead of 1 (family name)
3865 static LPWSTR load_ttfname_from(LPCWSTR filename)
3867 HANDLE handle;
3868 LPWSTR ret = NULL;
3869 int i;
3871 typedef struct _tagTT_OFFSET_TABLE{
3872 USHORT uMajorVersion;
3873 USHORT uMinorVersion;
3874 USHORT uNumOfTables;
3875 USHORT uSearchRange;
3876 USHORT uEntrySelector;
3877 USHORT uRangeShift;
3878 }TT_OFFSET_TABLE;
3880 typedef struct _tagTT_TABLE_DIRECTORY{
3881 char szTag[4]; /* table name */
3882 ULONG uCheckSum; /* Check sum */
3883 ULONG uOffset; /* Offset from beginning of file */
3884 ULONG uLength; /* length of the table in bytes */
3885 }TT_TABLE_DIRECTORY;
3887 typedef struct _tagTT_NAME_TABLE_HEADER{
3888 USHORT uFSelector; /* format selector. Always 0 */
3889 USHORT uNRCount; /* Name Records count */
3890 USHORT uStorageOffset; /* Offset for strings storage,
3891 * from start of the table */
3892 }TT_NAME_TABLE_HEADER;
3894 typedef struct _tagTT_NAME_RECORD{
3895 USHORT uPlatformID;
3896 USHORT uEncodingID;
3897 USHORT uLanguageID;
3898 USHORT uNameID;
3899 USHORT uStringLength;
3900 USHORT uStringOffset; /* from start of storage area */
3901 }TT_NAME_RECORD;
3903 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3904 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3906 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3907 FILE_ATTRIBUTE_NORMAL, 0 );
3908 if (handle != INVALID_HANDLE_VALUE)
3910 TT_TABLE_DIRECTORY tblDir;
3911 BOOL bFound = FALSE;
3912 TT_OFFSET_TABLE ttOffsetTable;
3913 DWORD dwRead;
3915 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3916 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3917 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3918 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3920 if (ttOffsetTable.uMajorVersion != 1 ||
3921 ttOffsetTable.uMinorVersion != 0)
3922 return NULL;
3924 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3926 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3927 if (strncmp(tblDir.szTag,"name",4)==0)
3929 bFound = TRUE;
3930 tblDir.uLength = SWAPLONG(tblDir.uLength);
3931 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3932 break;
3936 if (bFound)
3938 TT_NAME_TABLE_HEADER ttNTHeader;
3939 TT_NAME_RECORD ttRecord;
3941 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3942 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3943 &dwRead,NULL);
3945 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3946 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3947 bFound = FALSE;
3948 for(i=0; i<ttNTHeader.uNRCount; i++)
3950 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3951 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3952 /* 4 is the Full Font Name */
3953 if(ttRecord.uNameID == 4)
3955 int nPos;
3956 LPSTR buf;
3957 static LPCSTR tt = " (TrueType)";
3959 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3960 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3961 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3962 SetFilePointer(handle, tblDir.uOffset +
3963 ttRecord.uStringOffset +
3964 ttNTHeader.uStorageOffset,
3965 NULL, FILE_BEGIN);
3966 buf = msi_alloc_zero( ttRecord.uStringLength + 1 + strlen(tt) );
3967 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3968 if (strlen(buf) > 0)
3970 strcat(buf,tt);
3971 ret = strdupAtoW(buf);
3972 msi_free(buf);
3973 break;
3976 msi_free(buf);
3977 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3981 CloseHandle(handle);
3983 else
3984 ERR("Unable to open font file %s\n", debugstr_w(filename));
3986 TRACE("Returning fontname %s\n",debugstr_w(ret));
3987 return ret;
3990 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3992 MSIPACKAGE *package = (MSIPACKAGE*)param;
3993 LPWSTR name;
3994 LPCWSTR filename;
3995 MSIFILE *file;
3996 static const WCHAR regfont1[] =
3997 {'S','o','f','t','w','a','r','e','\\',
3998 'M','i','c','r','o','s','o','f','t','\\',
3999 'W','i','n','d','o','w','s',' ','N','T','\\',
4000 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4001 'F','o','n','t','s',0};
4002 static const WCHAR regfont2[] =
4003 {'S','o','f','t','w','a','r','e','\\',
4004 'M','i','c','r','o','s','o','f','t','\\',
4005 'W','i','n','d','o','w','s','\\',
4006 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4007 'F','o','n','t','s',0};
4008 HKEY hkey1;
4009 HKEY hkey2;
4010 MSIRECORD *uirow;
4011 LPWSTR uipath, p;
4013 filename = MSI_RecordGetString( row, 1 );
4014 file = get_loaded_file( package, filename );
4015 if (!file)
4017 ERR("Unable to load file\n");
4018 return ERROR_SUCCESS;
4021 /* check to make sure that component is installed */
4022 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
4024 TRACE("Skipping: Component not scheduled for install\n");
4025 return ERROR_SUCCESS;
4028 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
4029 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
4031 if (MSI_RecordIsNull(row,2))
4032 name = load_ttfname_from( file->TargetPath );
4033 else
4034 name = msi_dup_record_field(row,2);
4036 if (name)
4038 msi_reg_set_val_str( hkey1, name, file->FileName );
4039 msi_reg_set_val_str( hkey2, name, file->FileName );
4042 msi_free(name);
4043 RegCloseKey(hkey1);
4044 RegCloseKey(hkey2);
4046 /* the UI chunk */
4047 uirow = MSI_CreateRecord( 1 );
4048 uipath = strdupW( file->TargetPath );
4049 p = strrchrW(uipath,'\\');
4050 if (p) p++;
4051 else p = uipath;
4052 MSI_RecordSetStringW( uirow, 1, p );
4053 ui_actiondata( package, szRegisterFonts, uirow);
4054 msiobj_release( &uirow->hdr );
4055 msi_free( uipath );
4056 /* FIXME: call ui_progress? */
4058 return ERROR_SUCCESS;
4061 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4063 UINT rc;
4064 MSIQUERY * view;
4065 static const WCHAR ExecSeqQuery[] =
4066 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4067 '`','F','o','n','t','`',0};
4069 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4070 if (rc != ERROR_SUCCESS)
4072 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4073 return ERROR_SUCCESS;
4076 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4077 msiobj_release(&view->hdr);
4079 return ERROR_SUCCESS;
4082 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4084 MSIPACKAGE *package = (MSIPACKAGE*)param;
4085 LPCWSTR compgroupid=NULL;
4086 LPCWSTR feature=NULL;
4087 LPCWSTR text = NULL;
4088 LPCWSTR qualifier = NULL;
4089 LPCWSTR component = NULL;
4090 LPWSTR advertise = NULL;
4091 LPWSTR output = NULL;
4092 HKEY hkey;
4093 UINT rc = ERROR_SUCCESS;
4094 MSICOMPONENT *comp;
4095 DWORD sz = 0;
4096 MSIRECORD *uirow;
4098 component = MSI_RecordGetString(rec,3);
4099 comp = get_loaded_component(package,component);
4101 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4102 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4103 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4105 TRACE("Skipping: Component %s not scheduled for install\n",
4106 debugstr_w(component));
4108 return ERROR_SUCCESS;
4111 compgroupid = MSI_RecordGetString(rec,1);
4112 qualifier = MSI_RecordGetString(rec,2);
4114 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4115 if (rc != ERROR_SUCCESS)
4116 goto end;
4118 text = MSI_RecordGetString(rec,4);
4119 feature = MSI_RecordGetString(rec,5);
4121 advertise = create_component_advertise_string(package, comp, feature);
4123 sz = strlenW(advertise);
4125 if (text)
4126 sz += lstrlenW(text);
4128 sz+=3;
4129 sz *= sizeof(WCHAR);
4131 output = msi_alloc_zero(sz);
4132 strcpyW(output,advertise);
4133 msi_free(advertise);
4135 if (text)
4136 strcatW(output,text);
4138 msi_reg_set_val_multi_str( hkey, qualifier, output );
4140 end:
4141 RegCloseKey(hkey);
4142 msi_free(output);
4144 /* the UI chunk */
4145 uirow = MSI_CreateRecord( 2 );
4146 MSI_RecordSetStringW( uirow, 1, compgroupid );
4147 MSI_RecordSetStringW( uirow, 2, qualifier);
4148 ui_actiondata( package, szPublishComponents, uirow);
4149 msiobj_release( &uirow->hdr );
4150 /* FIXME: call ui_progress? */
4152 return rc;
4156 * At present I am ignorning the advertised components part of this and only
4157 * focusing on the qualified component sets
4159 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4161 UINT rc;
4162 MSIQUERY * view;
4163 static const WCHAR ExecSeqQuery[] =
4164 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4165 '`','P','u','b','l','i','s','h',
4166 'C','o','m','p','o','n','e','n','t','`',0};
4168 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4169 if (rc != ERROR_SUCCESS)
4170 return ERROR_SUCCESS;
4172 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4173 msiobj_release(&view->hdr);
4175 return rc;
4178 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4179 LPCSTR action, LPCWSTR table )
4181 static const WCHAR query[] = {
4182 'S','E','L','E','C','T',' ','*',' ',
4183 'F','R','O','M',' ','`','%','s','`',0 };
4184 MSIQUERY *view = NULL;
4185 DWORD count = 0;
4186 UINT r;
4188 r = MSI_OpenQuery( package->db, &view, query, table );
4189 if (r == ERROR_SUCCESS)
4191 r = MSI_IterateRecords(view, &count, NULL, package);
4192 msiobj_release(&view->hdr);
4195 if (count)
4196 FIXME("%s -> %lu ignored %s table values\n",
4197 action, count, debugstr_w(table));
4199 return ERROR_SUCCESS;
4202 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4204 TRACE("%p\n", package);
4205 return ERROR_SUCCESS;
4208 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4210 static const WCHAR table[] =
4211 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4212 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4215 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4217 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4218 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4221 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4223 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4224 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4227 static UINT ACTION_BindImage( MSIPACKAGE *package )
4229 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4230 return msi_unimplemented_action_stub( package, "BindImage", table );
4233 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4235 static const WCHAR table[] = {
4236 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4237 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4240 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4242 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4243 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4246 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4248 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4249 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4252 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4254 static const WCHAR table[] = {
4255 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4256 return msi_unimplemented_action_stub( package, "InstallServices", table );
4259 static UINT ACTION_StartServices( MSIPACKAGE *package )
4261 static const WCHAR table[] = {
4262 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4263 return msi_unimplemented_action_stub( package, "StartServices", table );
4266 static UINT ACTION_StopServices( MSIPACKAGE *package )
4268 static const WCHAR table[] = {
4269 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4270 return msi_unimplemented_action_stub( package, "StopServices", table );
4273 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4275 static const WCHAR table[] = {
4276 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4277 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4280 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4282 static const WCHAR table[] = {
4283 'E','n','v','i','r','o','n','m','e','n','t',0 };
4284 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4287 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4289 static const WCHAR table[] = {
4290 'E','n','v','i','r','o','n','m','e','n','t',0 };
4291 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4294 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4296 static const WCHAR table[] = {
4297 'M','s','i','A','s','s','e','m','b','l','y',0 };
4298 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4301 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4303 static const WCHAR table[] = {
4304 'M','s','i','A','s','s','e','m','b','l','y',0 };
4305 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4308 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4310 static const WCHAR table[] = { 'F','o','n','t',0 };
4311 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4314 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4316 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4317 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4320 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4322 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4323 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4326 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4328 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4329 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4332 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4334 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4335 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4338 static struct _actions StandardActions[] = {
4339 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4340 { szAppSearch, ACTION_AppSearch },
4341 { szBindImage, ACTION_BindImage },
4342 { szCCPSearch, ACTION_CCPSearch},
4343 { szCostFinalize, ACTION_CostFinalize },
4344 { szCostInitialize, ACTION_CostInitialize },
4345 { szCreateFolders, ACTION_CreateFolders },
4346 { szCreateShortcuts, ACTION_CreateShortcuts },
4347 { szDeleteServices, ACTION_DeleteServices },
4348 { szDisableRollback, NULL},
4349 { szDuplicateFiles, ACTION_DuplicateFiles },
4350 { szExecuteAction, ACTION_ExecuteAction },
4351 { szFileCost, ACTION_FileCost },
4352 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4353 { szForceReboot, ACTION_ForceReboot },
4354 { szInstallAdminPackage, NULL},
4355 { szInstallExecute, ACTION_InstallExecute },
4356 { szInstallExecuteAgain, ACTION_InstallExecute },
4357 { szInstallFiles, ACTION_InstallFiles},
4358 { szInstallFinalize, ACTION_InstallFinalize },
4359 { szInstallInitialize, ACTION_InstallInitialize },
4360 { szInstallSFPCatalogFile, NULL},
4361 { szInstallValidate, ACTION_InstallValidate },
4362 { szIsolateComponents, ACTION_IsolateComponents },
4363 { szLaunchConditions, ACTION_LaunchConditions },
4364 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4365 { szMoveFiles, ACTION_MoveFiles },
4366 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4367 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4368 { szInstallODBC, NULL},
4369 { szInstallServices, ACTION_InstallServices },
4370 { szPatchFiles, ACTION_PatchFiles },
4371 { szProcessComponents, ACTION_ProcessComponents },
4372 { szPublishComponents, ACTION_PublishComponents },
4373 { szPublishFeatures, ACTION_PublishFeatures },
4374 { szPublishProduct, ACTION_PublishProduct },
4375 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4376 { szRegisterComPlus, ACTION_RegisterComPlus},
4377 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4378 { szRegisterFonts, ACTION_RegisterFonts },
4379 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4380 { szRegisterProduct, ACTION_RegisterProduct },
4381 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4382 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4383 { szRegisterUser, ACTION_RegisterUser},
4384 { szRemoveDuplicateFiles, NULL},
4385 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4386 { szRemoveExistingProducts, NULL},
4387 { szRemoveFiles, ACTION_RemoveFiles},
4388 { szRemoveFolders, NULL},
4389 { szRemoveIniValues, ACTION_RemoveIniValues },
4390 { szRemoveODBC, NULL},
4391 { szRemoveRegistryValues, NULL},
4392 { szRemoveShortcuts, NULL},
4393 { szResolveSource, ACTION_ResolveSource},
4394 { szRMCCPSearch, ACTION_RMCCPSearch},
4395 { szScheduleReboot, NULL},
4396 { szSelfRegModules, ACTION_SelfRegModules },
4397 { szSelfUnregModules, ACTION_SelfUnregModules },
4398 { szSetODBCFolders, NULL},
4399 { szStartServices, ACTION_StartServices },
4400 { szStopServices, ACTION_StopServices },
4401 { szUnpublishComponents, NULL},
4402 { szUnpublishFeatures, NULL},
4403 { szUnregisterClassInfo, NULL},
4404 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4405 { szUnregisterExtensionInfo, NULL},
4406 { szUnregisterFonts, ACTION_UnregisterFonts },
4407 { szUnregisterMIMEInfo, NULL},
4408 { szUnregisterProgIdInfo, NULL},
4409 { szUnregisterTypeLibraries, NULL},
4410 { szValidateProductID, NULL},
4411 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4412 { szWriteIniValues, ACTION_WriteIniValues },
4413 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4414 { NULL, NULL},