push cc6891608c0bafd7b7a9ec5535ff0d2e018364e3
[wine/hacks.git] / dlls / msi / action.c
blobcc2583de61912477108451bf82adefd86b4aab89
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 "winsvc.h"
38 #include "odbcinst.h"
39 #include "wine/debug.h"
40 #include "msidefs.h"
41 #include "msipriv.h"
42 #include "winuser.h"
43 #include "shlobj.h"
44 #include "wine/unicode.h"
45 #include "winver.h"
47 #define REG_PROGRESS_VALUE 13200
48 #define COMPONENT_PROGRESS_VALUE 24000
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
53 * Prototypes
55 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
56 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
57 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
60 * consts and values used
62 static const WCHAR c_colon[] = {'C',':','\\',0};
64 static const WCHAR szCreateFolders[] =
65 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
66 static const WCHAR szCostFinalize[] =
67 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
68 const WCHAR szInstallFiles[] =
69 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
70 const WCHAR szDuplicateFiles[] =
71 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
72 static const WCHAR szWriteRegistryValues[] =
73 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
74 'V','a','l','u','e','s',0};
75 static const WCHAR szCostInitialize[] =
76 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
77 static const WCHAR szFileCost[] =
78 {'F','i','l','e','C','o','s','t',0};
79 static const WCHAR szInstallInitialize[] =
80 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
81 static const WCHAR szInstallValidate[] =
82 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
83 static const WCHAR szLaunchConditions[] =
84 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
85 static const WCHAR szProcessComponents[] =
86 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
87 static const WCHAR szRegisterTypeLibraries[] =
88 {'R','e','g','i','s','t','e','r','T','y','p','e',
89 'L','i','b','r','a','r','i','e','s',0};
90 const WCHAR szRegisterClassInfo[] =
91 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
92 const WCHAR szRegisterProgIdInfo[] =
93 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
94 static const WCHAR szCreateShortcuts[] =
95 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
96 static const WCHAR szPublishProduct[] =
97 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
98 static const WCHAR szWriteIniValues[] =
99 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
100 static const WCHAR szSelfRegModules[] =
101 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
102 static const WCHAR szPublishFeatures[] =
103 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
104 static const WCHAR szRegisterProduct[] =
105 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
106 static const WCHAR szInstallExecute[] =
107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
108 static const WCHAR szInstallExecuteAgain[] =
109 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
110 'A','g','a','i','n',0};
111 static const WCHAR szInstallFinalize[] =
112 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
113 static const WCHAR szForceReboot[] =
114 {'F','o','r','c','e','R','e','b','o','o','t',0};
115 static const WCHAR szResolveSource[] =
116 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
117 static const WCHAR szAppSearch[] =
118 {'A','p','p','S','e','a','r','c','h',0};
119 static const WCHAR szAllocateRegistrySpace[] =
120 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
121 'S','p','a','c','e',0};
122 static const WCHAR szBindImage[] =
123 {'B','i','n','d','I','m','a','g','e',0};
124 static const WCHAR szCCPSearch[] =
125 {'C','C','P','S','e','a','r','c','h',0};
126 static const WCHAR szDeleteServices[] =
127 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
128 static const WCHAR szDisableRollback[] =
129 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
130 static const WCHAR szExecuteAction[] =
131 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
132 const WCHAR szFindRelatedProducts[] =
133 {'F','i','n','d','R','e','l','a','t','e','d',
134 'P','r','o','d','u','c','t','s',0};
135 static const WCHAR szInstallAdminPackage[] =
136 {'I','n','s','t','a','l','l','A','d','m','i','n',
137 'P','a','c','k','a','g','e',0};
138 static const WCHAR szInstallSFPCatalogFile[] =
139 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 'F','i','l','e',0};
141 static const WCHAR szIsolateComponents[] =
142 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
143 const WCHAR szMigrateFeatureStates[] =
144 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
145 'S','t','a','t','e','s',0};
146 const WCHAR szMoveFiles[] =
147 {'M','o','v','e','F','i','l','e','s',0};
148 static const WCHAR szMsiPublishAssemblies[] =
149 {'M','s','i','P','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szMsiUnpublishAssemblies[] =
152 {'M','s','i','U','n','p','u','b','l','i','s','h',
153 'A','s','s','e','m','b','l','i','e','s',0};
154 static const WCHAR szInstallODBC[] =
155 {'I','n','s','t','a','l','l','O','D','B','C',0};
156 static const WCHAR szInstallServices[] =
157 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
158 const WCHAR szPatchFiles[] =
159 {'P','a','t','c','h','F','i','l','e','s',0};
160 static const WCHAR szPublishComponents[] =
161 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
162 static const WCHAR szRegisterComPlus[] =
163 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
164 const WCHAR szRegisterExtensionInfo[] =
165 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 'I','n','f','o',0};
167 static const WCHAR szRegisterFonts[] =
168 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
169 const WCHAR szRegisterMIMEInfo[] =
170 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
171 static const WCHAR szRegisterUser[] =
172 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
173 const WCHAR szRemoveDuplicateFiles[] =
174 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
175 'F','i','l','e','s',0};
176 static const WCHAR szRemoveEnvironmentStrings[] =
177 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
178 'S','t','r','i','n','g','s',0};
179 const WCHAR szRemoveExistingProducts[] =
180 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
181 'P','r','o','d','u','c','t','s',0};
182 const WCHAR szRemoveFiles[] =
183 {'R','e','m','o','v','e','F','i','l','e','s',0};
184 static const WCHAR szRemoveFolders[] =
185 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
186 static const WCHAR szRemoveIniValues[] =
187 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
188 static const WCHAR szRemoveODBC[] =
189 {'R','e','m','o','v','e','O','D','B','C',0};
190 static const WCHAR szRemoveRegistryValues[] =
191 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
192 'V','a','l','u','e','s',0};
193 static const WCHAR szRemoveShortcuts[] =
194 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
195 static const WCHAR szRMCCPSearch[] =
196 {'R','M','C','C','P','S','e','a','r','c','h',0};
197 static const WCHAR szScheduleReboot[] =
198 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
199 static const WCHAR szSelfUnregModules[] =
200 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
201 static const WCHAR szSetODBCFolders[] =
202 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
203 static const WCHAR szStartServices[] =
204 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
205 static const WCHAR szStopServices[] =
206 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
207 static const WCHAR szUnpublishComponents[] =
208 {'U','n','p','u','b','l','i','s','h',
209 'C','o','m','p','o','n','e','n','t','s',0};
210 static const WCHAR szUnpublishFeatures[] =
211 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
212 const WCHAR szUnregisterClassInfo[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 'I','n','f','o',0};
215 static const WCHAR szUnregisterComPlus[] =
216 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const WCHAR szUnregisterExtensionInfo[] =
218 {'U','n','r','e','g','i','s','t','e','r',
219 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
220 static const WCHAR szUnregisterFonts[] =
221 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const WCHAR szUnregisterMIMEInfo[] =
223 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const WCHAR szUnregisterProgIdInfo[] =
225 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 'I','n','f','o',0};
227 static const WCHAR szUnregisterTypeLibraries[] =
228 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
229 'L','i','b','r','a','r','i','e','s',0};
230 static const WCHAR szValidateProductID[] =
231 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
232 static const WCHAR szWriteEnvironmentStrings[] =
233 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
234 'S','t','r','i','n','g','s',0};
236 /* action handlers */
237 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
239 struct _actions {
240 LPCWSTR action;
241 STANDARDACTIONHANDLER handler;
244 static const struct _actions StandardActions[];
247 /********************************************************
248 * helper functions
249 ********************************************************/
251 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
253 static const WCHAR Query_t[] =
254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
255 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
256 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
257 ' ','\'','%','s','\'',0};
258 MSIRECORD * row;
260 row = MSI_QueryGetRecord( package->db, Query_t, action );
261 if (!row)
262 return;
263 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
264 msiobj_release(&row->hdr);
267 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
268 UINT rc)
270 MSIRECORD * row;
271 static const WCHAR template_s[]=
272 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 '%','s', '.',0};
274 static const WCHAR template_e[]=
275 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
276 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 '%','i','.',0};
278 static const WCHAR format[] =
279 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
280 WCHAR message[1024];
281 WCHAR timet[0x100];
283 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 if (start)
285 sprintfW(message,template_s,timet,action);
286 else
287 sprintfW(message,template_e,timet,action,rc);
289 row = MSI_CreateRecord(1);
290 MSI_RecordSetStringW(row,1,message);
292 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
293 msiobj_release(&row->hdr);
296 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
298 LPCWSTR ptr,ptr2;
299 BOOL quote;
300 DWORD len;
301 LPWSTR prop = NULL, val = NULL;
303 if (!szCommandLine)
304 return ERROR_SUCCESS;
306 ptr = szCommandLine;
308 while (*ptr)
310 if (*ptr==' ')
312 ptr++;
313 continue;
316 TRACE("Looking at %s\n",debugstr_w(ptr));
318 ptr2 = strchrW(ptr,'=');
319 if (!ptr2)
321 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
322 break;
325 quote = FALSE;
327 len = ptr2-ptr;
328 prop = msi_alloc((len+1)*sizeof(WCHAR));
329 memcpy(prop,ptr,len*sizeof(WCHAR));
330 prop[len]=0;
331 ptr2++;
333 len = 0;
334 ptr = ptr2;
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
337 if (*ptr == '"')
338 quote = !quote;
339 ptr++;
340 len++;
343 if (*ptr2=='"')
345 ptr2++;
346 len -= 2;
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
350 val[len] = 0;
352 if (lstrlenW(prop) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
358 msi_free(val);
359 msi_free(prop);
362 return ERROR_SUCCESS;
366 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
368 LPCWSTR pc;
369 LPWSTR p, *ret = NULL;
370 UINT count = 0;
372 if (!str)
373 return ret;
375 /* count the number of substrings */
376 for ( pc = str, count = 0; pc; count++ )
378 pc = strchrW( pc, sep );
379 if (pc)
380 pc++;
383 /* allocate space for an array of substring pointers and the substrings */
384 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
385 (lstrlenW(str)+1) * sizeof(WCHAR) );
386 if (!ret)
387 return ret;
389 /* copy the string and set the pointers */
390 p = (LPWSTR) &ret[count+1];
391 lstrcpyW( p, str );
392 for( count = 0; (ret[count] = p); count++ )
394 p = strchrW( p, sep );
395 if (p)
396 *p++ = 0;
399 return ret;
402 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
404 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code, patch_product;
406 UINT ret;
408 prod_code = msi_dup_property( package, szProductCode );
409 patch_product = msi_get_suminfo_product( patch );
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
413 if ( strstrW( patch_product, prod_code ) )
414 ret = ERROR_SUCCESS;
415 else
416 ret = ERROR_FUNCTION_FAILED;
418 msi_free( patch_product );
419 msi_free( prod_code );
421 return ret;
424 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
425 MSIDATABASE *patch_db, LPCWSTR name )
427 UINT ret = ERROR_FUNCTION_FAILED;
428 IStorage *stg = NULL;
429 HRESULT r;
431 TRACE("%p %s\n", package, debugstr_w(name) );
433 if (*name++ != ':')
435 ERR("expected a colon in %s\n", debugstr_w(name));
436 return ERROR_FUNCTION_FAILED;
439 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
440 if (SUCCEEDED(r))
442 ret = msi_check_transform_applicable( package, stg );
443 if (ret == ERROR_SUCCESS)
444 msi_table_apply_transform( package->db, stg );
445 else
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
447 IStorage_Release( stg );
449 else
450 ERR("failed to open substorage %s\n", debugstr_w(name));
452 return ERROR_SUCCESS;
455 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
457 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list, *guids, product_code;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
461 product_code = msi_dup_property( package, szProdCode );
462 if (!product_code)
464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
466 return ERROR_SUCCESS;
469 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
470 guids = msi_split_string( guid_list, ';' );
471 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
473 if (!lstrcmpW( guids[i], product_code ))
474 ret = ERROR_SUCCESS;
476 msi_free( guids );
477 msi_free( guid_list );
478 msi_free( product_code );
480 return ret;
483 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
485 MSISUMMARYINFO *si;
486 LPWSTR str, *substorage;
487 UINT i, r = ERROR_SUCCESS;
489 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
490 if (!si)
491 return ERROR_FUNCTION_FAILED;
493 msi_check_patch_applicable( package, si );
495 /* enumerate the substorage */
496 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
497 substorage = msi_split_string( str, ';' );
498 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
499 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
500 msi_free( substorage );
501 msi_free( str );
503 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
505 msiobj_release( &si->hdr );
507 return r;
510 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
512 MSIDATABASE *patch_db = NULL;
513 UINT r;
515 TRACE("%p %s\n", package, debugstr_w( file ) );
517 /* FIXME:
518 * We probably want to make sure we only open a patch collection here.
519 * Patch collections (.msp) and databases (.msi) have different GUIDs
520 * but currently MSI_OpenDatabaseW will accept both.
522 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
523 if ( r != ERROR_SUCCESS )
525 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
526 return r;
529 msi_parse_patch_summary( package, patch_db );
532 * There might be a CAB file in the patch package,
533 * so append it to the list of storage to search for streams.
535 append_storage_to_db( package->db, patch_db->storage );
537 msiobj_release( &patch_db->hdr );
539 return ERROR_SUCCESS;
542 /* get the PATCH property, and apply all the patches it specifies */
543 static UINT msi_apply_patches( MSIPACKAGE *package )
545 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
546 LPWSTR patch_list, *patches;
547 UINT i, r = ERROR_SUCCESS;
549 patch_list = msi_dup_property( package, szPatch );
551 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
553 patches = msi_split_string( patch_list, ';' );
554 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
555 r = msi_apply_patch_package( package, patches[i] );
557 msi_free( patches );
558 msi_free( patch_list );
560 return r;
563 static UINT msi_apply_transforms( MSIPACKAGE *package )
565 static const WCHAR szTransforms[] = {
566 'T','R','A','N','S','F','O','R','M','S',0 };
567 LPWSTR xform_list, *xforms;
568 UINT i, r = ERROR_SUCCESS;
570 xform_list = msi_dup_property( package, szTransforms );
571 xforms = msi_split_string( xform_list, ';' );
573 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
575 if (xforms[i][0] == ':')
576 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
577 else
578 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
581 msi_free( xforms );
582 msi_free( xform_list );
584 return r;
587 BOOL ui_sequence_exists( MSIPACKAGE *package )
589 MSIQUERY *view;
590 UINT rc;
592 static const WCHAR ExecSeqQuery [] =
593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
594 '`','I','n','s','t','a','l','l',
595 'U','I','S','e','q','u','e','n','c','e','`',
596 ' ','W','H','E','R','E',' ',
597 '`','S','e','q','u','e','n','c','e','`',' ',
598 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
599 '`','S','e','q','u','e','n','c','e','`',0};
601 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
602 if (rc == ERROR_SUCCESS)
604 msiobj_release(&view->hdr);
605 return TRUE;
608 return FALSE;
611 /****************************************************
612 * TOP level entry points
613 *****************************************************/
615 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
616 LPCWSTR szCommandLine )
618 UINT rc;
619 BOOL ui = FALSE, ui_exists;
620 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
621 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
622 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
624 MSI_SetPropertyW(package, szAction, szInstall);
626 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
628 package->script->InWhatSequence = SEQUENCE_INSTALL;
630 if (szPackagePath)
632 LPWSTR p, check, path;
634 path = strdupW(szPackagePath);
635 p = strrchrW(path,'\\');
636 if (p)
638 p++;
639 *p=0;
641 else
643 msi_free(path);
644 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
645 GetCurrentDirectoryW(MAX_PATH,path);
646 strcatW(path,cszbs);
649 check = msi_dup_property( package, cszSourceDir );
650 if (!check)
651 MSI_SetPropertyW(package, cszSourceDir, path);
652 msi_free(check);
654 check = msi_dup_property( package, cszSOURCEDIR );
655 if (!check)
656 MSI_SetPropertyW(package, cszSOURCEDIR, path);
658 msi_free( package->PackagePath );
659 package->PackagePath = path;
661 msi_free(check);
664 msi_parse_command_line( package, szCommandLine );
666 msi_apply_transforms( package );
667 msi_apply_patches( package );
669 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
671 package->script->InWhatSequence |= SEQUENCE_UI;
672 rc = ACTION_ProcessUISequence(package);
673 ui = TRUE;
674 ui_exists = ui_sequence_exists(package);
675 if (rc == ERROR_SUCCESS || !ui_exists)
677 package->script->InWhatSequence |= SEQUENCE_EXEC;
678 rc = ACTION_ProcessExecSequence(package,ui_exists);
681 else
682 rc = ACTION_ProcessExecSequence(package,FALSE);
684 if (rc == -1)
686 /* install was halted but should be considered a success */
687 rc = ERROR_SUCCESS;
690 package->script->CurrentlyScripting= FALSE;
692 /* process the ending type action */
693 if (rc == ERROR_SUCCESS)
694 ACTION_PerformActionSequence(package,-1,ui);
695 else if (rc == ERROR_INSTALL_USEREXIT)
696 ACTION_PerformActionSequence(package,-2,ui);
697 else if (rc == ERROR_INSTALL_SUSPEND)
698 ACTION_PerformActionSequence(package,-4,ui);
699 else /* failed */
700 ACTION_PerformActionSequence(package,-3,ui);
702 /* finish up running custom actions */
703 ACTION_FinishCustomActions(package);
705 return rc;
708 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
710 UINT rc = ERROR_SUCCESS;
711 MSIRECORD * row = 0;
712 static const WCHAR ExecSeqQuery[] =
713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
714 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
715 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
716 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
718 static const WCHAR UISeqQuery[] =
719 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
720 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
721 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
722 ' ', '=',' ','%','i',0};
724 if (UI)
725 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
726 else
727 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
729 if (row)
731 LPCWSTR action, cond;
733 TRACE("Running the actions\n");
735 /* check conditions */
736 cond = MSI_RecordGetString(row,2);
738 /* this is a hack to skip errors in the condition code */
739 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
740 goto end;
742 action = MSI_RecordGetString(row,1);
743 if (!action)
745 ERR("failed to fetch action\n");
746 rc = ERROR_FUNCTION_FAILED;
747 goto end;
750 if (UI)
751 rc = ACTION_PerformUIAction(package,action,-1);
752 else
753 rc = ACTION_PerformAction(package,action,-1,FALSE);
754 end:
755 msiobj_release(&row->hdr);
757 else
758 rc = ERROR_SUCCESS;
760 return rc;
763 typedef struct {
764 MSIPACKAGE* package;
765 BOOL UI;
766 } iterate_action_param;
768 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
770 iterate_action_param *iap= (iterate_action_param*)param;
771 UINT rc;
772 LPCWSTR cond, action;
774 action = MSI_RecordGetString(row,1);
775 if (!action)
777 ERR("Error is retrieving action name\n");
778 return ERROR_FUNCTION_FAILED;
781 /* check conditions */
782 cond = MSI_RecordGetString(row,2);
784 /* this is a hack to skip errors in the condition code */
785 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
787 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
788 return ERROR_SUCCESS;
791 if (iap->UI)
792 rc = ACTION_PerformUIAction(iap->package,action,-1);
793 else
794 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
796 msi_dialog_check_messages( NULL );
798 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
799 rc = iap->package->CurrentInstallState;
801 if (rc == ERROR_FUNCTION_NOT_CALLED)
802 rc = ERROR_SUCCESS;
804 if (rc != ERROR_SUCCESS)
805 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
807 return rc;
810 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
812 MSIQUERY * view;
813 UINT r;
814 static const WCHAR query[] =
815 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
816 '`','%','s','`',
817 ' ','W','H','E','R','E',' ',
818 '`','S','e','q','u','e','n','c','e','`',' ',
819 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
820 '`','S','e','q','u','e','n','c','e','`',0};
821 iterate_action_param iap;
824 * FIXME: probably should be checking UILevel in the
825 * ACTION_PerformUIAction/ACTION_PerformAction
826 * rather than saving the UI level here. Those
827 * two functions can be merged too.
829 iap.package = package;
830 iap.UI = TRUE;
832 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
834 r = MSI_OpenQuery( package->db, &view, query, szTable );
835 if (r == ERROR_SUCCESS)
837 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
838 msiobj_release(&view->hdr);
841 return r;
844 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
846 MSIQUERY * view;
847 UINT rc;
848 static const WCHAR ExecSeqQuery[] =
849 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
850 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
851 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
852 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
853 'O','R','D','E','R',' ', 'B','Y',' ',
854 '`','S','e','q','u','e','n','c','e','`',0 };
855 MSIRECORD * row = 0;
856 static const WCHAR IVQuery[] =
857 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
858 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
859 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
860 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
861 ' ','\'', 'I','n','s','t','a','l','l',
862 'V','a','l','i','d','a','t','e','\'', 0};
863 INT seq = 0;
864 iterate_action_param iap;
866 iap.package = package;
867 iap.UI = FALSE;
869 if (package->script->ExecuteSequenceRun)
871 TRACE("Execute Sequence already Run\n");
872 return ERROR_SUCCESS;
875 package->script->ExecuteSequenceRun = TRUE;
877 /* get the sequence number */
878 if (UIran)
880 row = MSI_QueryGetRecord(package->db, IVQuery);
881 if( !row )
882 return ERROR_FUNCTION_FAILED;
883 seq = MSI_RecordGetInteger(row,1);
884 msiobj_release(&row->hdr);
887 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
888 if (rc == ERROR_SUCCESS)
890 TRACE("Running the actions\n");
892 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
893 msiobj_release(&view->hdr);
896 return rc;
899 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
901 MSIQUERY * view;
902 UINT rc;
903 static const WCHAR ExecSeqQuery [] =
904 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
905 '`','I','n','s','t','a','l','l',
906 'U','I','S','e','q','u','e','n','c','e','`',
907 ' ','W','H','E','R','E',' ',
908 '`','S','e','q','u','e','n','c','e','`',' ',
909 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
910 '`','S','e','q','u','e','n','c','e','`',0};
911 iterate_action_param iap;
913 iap.package = package;
914 iap.UI = TRUE;
916 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
918 if (rc == ERROR_SUCCESS)
920 TRACE("Running the actions\n");
922 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
923 msiobj_release(&view->hdr);
926 return rc;
929 /********************************************************
930 * ACTION helper functions and functions that perform the actions
931 *******************************************************/
932 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
933 UINT* rc, BOOL force )
935 BOOL ret = FALSE;
936 BOOL run = force;
937 int i;
939 if (!run && !package->script->CurrentlyScripting)
940 run = TRUE;
942 if (!run)
944 if (strcmpW(action,szInstallFinalize) == 0 ||
945 strcmpW(action,szInstallExecute) == 0 ||
946 strcmpW(action,szInstallExecuteAgain) == 0)
947 run = TRUE;
950 i = 0;
951 while (StandardActions[i].action != NULL)
953 if (strcmpW(StandardActions[i].action, action)==0)
955 if (!run)
957 ui_actioninfo(package, action, TRUE, 0);
958 *rc = schedule_action(package,INSTALL_SCRIPT,action);
959 ui_actioninfo(package, action, FALSE, *rc);
961 else
963 ui_actionstart(package, action);
964 if (StandardActions[i].handler)
966 *rc = StandardActions[i].handler(package);
968 else
970 FIXME("unhandled standard action %s\n",debugstr_w(action));
971 *rc = ERROR_SUCCESS;
974 ret = TRUE;
975 break;
977 i++;
979 return ret;
982 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
983 UINT* rc, UINT script, BOOL force )
985 BOOL ret=FALSE;
986 UINT arc;
988 arc = ACTION_CustomAction(package, action, script, force);
990 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
992 *rc = arc;
993 ret = TRUE;
995 return ret;
999 * A lot of actions are really important even if they don't do anything
1000 * explicit... Lots of properties are set at the beginning of the installation
1001 * CostFinalize does a bunch of work to translate the directories and such
1003 * But until I get write access to the database that is hard, so I am going to
1004 * hack it to see if I can get something to run.
1006 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1008 UINT rc = ERROR_SUCCESS;
1009 BOOL handled;
1011 TRACE("Performing action (%s)\n",debugstr_w(action));
1013 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1015 if (!handled)
1016 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1018 if (!handled)
1020 FIXME("unhandled msi action %s\n",debugstr_w(action));
1021 rc = ERROR_FUNCTION_NOT_CALLED;
1024 return rc;
1027 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1029 UINT rc = ERROR_SUCCESS;
1030 BOOL handled = FALSE;
1032 TRACE("Performing action (%s)\n",debugstr_w(action));
1034 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1036 if (!handled)
1037 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1039 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1040 handled = TRUE;
1042 if (!handled)
1044 FIXME("unhandled msi action %s\n",debugstr_w(action));
1045 rc = ERROR_FUNCTION_NOT_CALLED;
1048 return rc;
1053 * Actual Action Handlers
1056 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1058 MSIPACKAGE *package = (MSIPACKAGE*)param;
1059 LPCWSTR dir;
1060 LPWSTR full_path;
1061 MSIRECORD *uirow;
1062 MSIFOLDER *folder;
1064 dir = MSI_RecordGetString(row,1);
1065 if (!dir)
1067 ERR("Unable to get folder id\n");
1068 return ERROR_SUCCESS;
1071 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1072 if (!full_path)
1074 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1075 return ERROR_SUCCESS;
1078 TRACE("Folder is %s\n",debugstr_w(full_path));
1080 /* UI stuff */
1081 uirow = MSI_CreateRecord(1);
1082 MSI_RecordSetStringW(uirow,1,full_path);
1083 ui_actiondata(package,szCreateFolders,uirow);
1084 msiobj_release( &uirow->hdr );
1086 if (folder->State == 0)
1087 create_full_pathW(full_path);
1089 folder->State = 3;
1091 msi_free(full_path);
1092 return ERROR_SUCCESS;
1095 /* FIXME: probably should merge this with the above function */
1096 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1098 UINT rc = ERROR_SUCCESS;
1099 MSIFOLDER *folder;
1100 LPWSTR install_path;
1102 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1103 if (!install_path)
1104 return ERROR_FUNCTION_FAILED;
1106 /* create the path */
1107 if (folder->State == 0)
1109 create_full_pathW(install_path);
1110 folder->State = 2;
1112 msi_free(install_path);
1114 return rc;
1117 UINT msi_create_component_directories( MSIPACKAGE *package )
1119 MSICOMPONENT *comp;
1121 /* create all the folders required by the components are going to install */
1122 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1124 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1125 continue;
1126 msi_create_directory( package, comp->Directory );
1129 return ERROR_SUCCESS;
1133 * Also we cannot enable/disable components either, so for now I am just going
1134 * to do all the directories for all the components.
1136 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1138 static const WCHAR ExecSeqQuery[] =
1139 {'S','E','L','E','C','T',' ',
1140 '`','D','i','r','e','c','t','o','r','y','_','`',
1141 ' ','F','R','O','M',' ',
1142 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1143 UINT rc;
1144 MSIQUERY *view;
1146 /* create all the empty folders specified in the CreateFolder table */
1147 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1148 if (rc != ERROR_SUCCESS)
1149 return ERROR_SUCCESS;
1151 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1152 msiobj_release(&view->hdr);
1154 msi_create_component_directories( package );
1156 return rc;
1159 static UINT load_component( MSIRECORD *row, LPVOID param )
1161 MSIPACKAGE *package = param;
1162 MSICOMPONENT *comp;
1164 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1165 if (!comp)
1166 return ERROR_FUNCTION_FAILED;
1168 list_add_tail( &package->components, &comp->entry );
1170 /* fill in the data */
1171 comp->Component = msi_dup_record_field( row, 1 );
1173 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1175 comp->ComponentId = msi_dup_record_field( row, 2 );
1176 comp->Directory = msi_dup_record_field( row, 3 );
1177 comp->Attributes = MSI_RecordGetInteger(row,4);
1178 comp->Condition = msi_dup_record_field( row, 5 );
1179 comp->KeyPath = msi_dup_record_field( row, 6 );
1181 comp->Installed = INSTALLSTATE_UNKNOWN;
1182 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1184 return ERROR_SUCCESS;
1187 static UINT load_all_components( MSIPACKAGE *package )
1189 static const WCHAR query[] = {
1190 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1191 '`','C','o','m','p','o','n','e','n','t','`',0 };
1192 MSIQUERY *view;
1193 UINT r;
1195 if (!list_empty(&package->components))
1196 return ERROR_SUCCESS;
1198 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1199 if (r != ERROR_SUCCESS)
1200 return r;
1202 r = MSI_IterateRecords(view, NULL, load_component, package);
1203 msiobj_release(&view->hdr);
1204 return r;
1207 typedef struct {
1208 MSIPACKAGE *package;
1209 MSIFEATURE *feature;
1210 } _ilfs;
1212 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1214 ComponentList *cl;
1216 cl = msi_alloc( sizeof (*cl) );
1217 if ( !cl )
1218 return ERROR_NOT_ENOUGH_MEMORY;
1219 cl->component = comp;
1220 list_add_tail( &feature->Components, &cl->entry );
1222 return ERROR_SUCCESS;
1225 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1227 FeatureList *fl;
1229 fl = msi_alloc( sizeof(*fl) );
1230 if ( !fl )
1231 return ERROR_NOT_ENOUGH_MEMORY;
1232 fl->feature = child;
1233 list_add_tail( &parent->Children, &fl->entry );
1235 return ERROR_SUCCESS;
1238 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1240 _ilfs* ilfs= (_ilfs*)param;
1241 LPCWSTR component;
1242 MSICOMPONENT *comp;
1244 component = MSI_RecordGetString(row,1);
1246 /* check to see if the component is already loaded */
1247 comp = get_loaded_component( ilfs->package, component );
1248 if (!comp)
1250 ERR("unknown component %s\n", debugstr_w(component));
1251 return ERROR_FUNCTION_FAILED;
1254 add_feature_component( ilfs->feature, comp );
1255 comp->Enabled = TRUE;
1257 return ERROR_SUCCESS;
1260 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1262 MSIFEATURE *feature;
1264 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1266 if ( !lstrcmpW( feature->Feature, name ) )
1267 return feature;
1270 return NULL;
1273 static UINT load_feature(MSIRECORD * row, LPVOID param)
1275 MSIPACKAGE* package = (MSIPACKAGE*)param;
1276 MSIFEATURE* feature;
1277 static const WCHAR Query1[] =
1278 {'S','E','L','E','C','T',' ',
1279 '`','C','o','m','p','o','n','e','n','t','_','`',
1280 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1281 'C','o','m','p','o','n','e','n','t','s','`',' ',
1282 'W','H','E','R','E',' ',
1283 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1284 MSIQUERY * view;
1285 UINT rc;
1286 _ilfs ilfs;
1288 /* fill in the data */
1290 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1291 if (!feature)
1292 return ERROR_NOT_ENOUGH_MEMORY;
1294 list_init( &feature->Children );
1295 list_init( &feature->Components );
1297 feature->Feature = msi_dup_record_field( row, 1 );
1299 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1301 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1302 feature->Title = msi_dup_record_field( row, 3 );
1303 feature->Description = msi_dup_record_field( row, 4 );
1305 if (!MSI_RecordIsNull(row,5))
1306 feature->Display = MSI_RecordGetInteger(row,5);
1308 feature->Level= MSI_RecordGetInteger(row,6);
1309 feature->Directory = msi_dup_record_field( row, 7 );
1310 feature->Attributes = MSI_RecordGetInteger(row,8);
1312 feature->Installed = INSTALLSTATE_UNKNOWN;
1313 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1315 list_add_tail( &package->features, &feature->entry );
1317 /* load feature components */
1319 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1320 if (rc != ERROR_SUCCESS)
1321 return ERROR_SUCCESS;
1323 ilfs.package = package;
1324 ilfs.feature = feature;
1326 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1327 msiobj_release(&view->hdr);
1329 return ERROR_SUCCESS;
1332 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1334 MSIPACKAGE* package = (MSIPACKAGE*)param;
1335 MSIFEATURE *parent, *child;
1337 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1338 if (!child)
1339 return ERROR_FUNCTION_FAILED;
1341 if (!child->Feature_Parent)
1342 return ERROR_SUCCESS;
1344 parent = find_feature_by_name( package, child->Feature_Parent );
1345 if (!parent)
1346 return ERROR_FUNCTION_FAILED;
1348 add_feature_child( parent, child );
1349 return ERROR_SUCCESS;
1352 static UINT load_all_features( MSIPACKAGE *package )
1354 static const WCHAR query[] = {
1355 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1356 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1357 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1358 MSIQUERY *view;
1359 UINT r;
1361 if (!list_empty(&package->features))
1362 return ERROR_SUCCESS;
1364 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1365 if (r != ERROR_SUCCESS)
1366 return r;
1368 r = MSI_IterateRecords( view, NULL, load_feature, package );
1369 if (r != ERROR_SUCCESS)
1370 return r;
1372 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1373 msiobj_release( &view->hdr );
1375 return r;
1378 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1380 if (!p)
1381 return p;
1382 p = strchrW(p, ch);
1383 if (!p)
1384 return p;
1385 *p = 0;
1386 return p+1;
1389 static UINT load_file(MSIRECORD *row, LPVOID param)
1391 MSIPACKAGE* package = (MSIPACKAGE*)param;
1392 LPCWSTR component;
1393 MSIFILE *file;
1395 /* fill in the data */
1397 file = msi_alloc_zero( sizeof (MSIFILE) );
1398 if (!file)
1399 return ERROR_NOT_ENOUGH_MEMORY;
1401 file->File = msi_dup_record_field( row, 1 );
1403 component = MSI_RecordGetString( row, 2 );
1404 file->Component = get_loaded_component( package, component );
1406 if (!file->Component)
1407 ERR("Unfound Component %s\n",debugstr_w(component));
1409 file->FileName = msi_dup_record_field( row, 3 );
1410 reduce_to_longfilename( file->FileName );
1412 file->ShortName = msi_dup_record_field( row, 3 );
1413 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1415 file->FileSize = MSI_RecordGetInteger( row, 4 );
1416 file->Version = msi_dup_record_field( row, 5 );
1417 file->Language = msi_dup_record_field( row, 6 );
1418 file->Attributes = MSI_RecordGetInteger( row, 7 );
1419 file->Sequence = MSI_RecordGetInteger( row, 8 );
1421 file->state = msifs_invalid;
1423 /* if the compressed bits are not set in the file attributes,
1424 * then read the information from the package word count property
1426 if (file->Attributes & msidbFileAttributesCompressed)
1428 file->IsCompressed = TRUE;
1430 else if (file->Attributes & msidbFileAttributesNoncompressed)
1432 file->IsCompressed = FALSE;
1434 else
1436 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1439 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1441 list_add_tail( &package->files, &file->entry );
1443 return ERROR_SUCCESS;
1446 static UINT load_all_files(MSIPACKAGE *package)
1448 MSIQUERY * view;
1449 UINT rc;
1450 static const WCHAR Query[] =
1451 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1452 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1453 '`','S','e','q','u','e','n','c','e','`', 0};
1455 if (!list_empty(&package->files))
1456 return ERROR_SUCCESS;
1458 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1459 if (rc != ERROR_SUCCESS)
1460 return ERROR_SUCCESS;
1462 rc = MSI_IterateRecords(view, NULL, load_file, package);
1463 msiobj_release(&view->hdr);
1465 return ERROR_SUCCESS;
1468 static UINT load_folder( MSIRECORD *row, LPVOID param )
1470 MSIPACKAGE *package = param;
1471 static const WCHAR szDot[] = { '.',0 };
1472 static WCHAR szEmpty[] = { 0 };
1473 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1474 MSIFOLDER *folder;
1476 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1477 if (!folder)
1478 return ERROR_NOT_ENOUGH_MEMORY;
1480 folder->Directory = msi_dup_record_field( row, 1 );
1482 TRACE("%s\n", debugstr_w(folder->Directory));
1484 p = msi_dup_record_field(row, 3);
1486 /* split src and target dir */
1487 tgt_short = p;
1488 src_short = folder_split_path( p, ':' );
1490 /* split the long and short paths */
1491 tgt_long = folder_split_path( tgt_short, '|' );
1492 src_long = folder_split_path( src_short, '|' );
1494 /* check for no-op dirs */
1495 if (!lstrcmpW(szDot, tgt_short))
1496 tgt_short = szEmpty;
1497 if (!lstrcmpW(szDot, src_short))
1498 src_short = szEmpty;
1500 if (!tgt_long)
1501 tgt_long = tgt_short;
1503 if (!src_short) {
1504 src_short = tgt_short;
1505 src_long = tgt_long;
1508 if (!src_long)
1509 src_long = src_short;
1511 /* FIXME: use the target short path too */
1512 folder->TargetDefault = strdupW(tgt_long);
1513 folder->SourceShortPath = strdupW(src_short);
1514 folder->SourceLongPath = strdupW(src_long);
1515 msi_free(p);
1517 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1518 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1519 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1521 folder->Parent = msi_dup_record_field( row, 2 );
1523 folder->Property = msi_dup_property( package, folder->Directory );
1525 list_add_tail( &package->folders, &folder->entry );
1527 TRACE("returning %p\n", folder);
1529 return ERROR_SUCCESS;
1532 static UINT load_all_folders( MSIPACKAGE *package )
1534 static const WCHAR query[] = {
1535 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1536 '`','D','i','r','e','c','t','o','r','y','`',0 };
1537 MSIQUERY *view;
1538 UINT r;
1540 if (!list_empty(&package->folders))
1541 return ERROR_SUCCESS;
1543 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1544 if (r != ERROR_SUCCESS)
1545 return r;
1547 r = MSI_IterateRecords(view, NULL, load_folder, package);
1548 msiobj_release(&view->hdr);
1549 return r;
1553 * I am not doing any of the costing functionality yet.
1554 * Mostly looking at doing the Component and Feature loading
1556 * The native MSI does A LOT of modification to tables here. Mostly adding
1557 * a lot of temporary columns to the Feature and Component tables.
1559 * note: Native msi also tracks the short filename. But I am only going to
1560 * track the long ones. Also looking at this directory table
1561 * it appears that the directory table does not get the parents
1562 * resolved base on property only based on their entries in the
1563 * directory table.
1565 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1567 static const WCHAR szCosting[] =
1568 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1569 static const WCHAR szZero[] = { '0', 0 };
1571 MSI_SetPropertyW(package, szCosting, szZero);
1572 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1574 load_all_components( package );
1575 load_all_features( package );
1576 load_all_files( package );
1577 load_all_folders( package );
1579 return ERROR_SUCCESS;
1582 static UINT execute_script(MSIPACKAGE *package, UINT script )
1584 int i;
1585 UINT rc = ERROR_SUCCESS;
1587 TRACE("Executing Script %i\n",script);
1589 if (!package->script)
1591 ERR("no script!\n");
1592 return ERROR_FUNCTION_FAILED;
1595 for (i = 0; i < package->script->ActionCount[script]; i++)
1597 LPWSTR action;
1598 action = package->script->Actions[script][i];
1599 ui_actionstart(package, action);
1600 TRACE("Executing Action (%s)\n",debugstr_w(action));
1601 rc = ACTION_PerformAction(package, action, script, TRUE);
1602 if (rc != ERROR_SUCCESS)
1603 break;
1605 msi_free_action_script(package, script);
1606 return rc;
1609 static UINT ACTION_FileCost(MSIPACKAGE *package)
1611 return ERROR_SUCCESS;
1614 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1616 MSICOMPONENT *comp;
1618 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1620 INSTALLSTATE res;
1622 if (!comp->ComponentId)
1623 continue;
1625 res = MsiGetComponentPathW( package->ProductCode,
1626 comp->ComponentId, NULL, NULL);
1627 if (res < 0)
1628 res = INSTALLSTATE_ABSENT;
1629 comp->Installed = res;
1633 /* scan for and update current install states */
1634 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1636 MSICOMPONENT *comp;
1637 MSIFEATURE *feature;
1639 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1641 ComponentList *cl;
1642 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1644 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1646 comp= cl->component;
1648 if (!comp->ComponentId)
1650 res = INSTALLSTATE_ABSENT;
1651 break;
1654 if (res == INSTALLSTATE_ABSENT)
1655 res = comp->Installed;
1656 else
1658 if (res == comp->Installed)
1659 continue;
1661 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1662 res != INSTALLSTATE_SOURCE)
1664 res = INSTALLSTATE_INCOMPLETE;
1668 feature->Installed = res;
1672 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1673 INSTALLSTATE state)
1675 static const WCHAR all[]={'A','L','L',0};
1676 LPWSTR override;
1677 MSIFEATURE *feature;
1679 override = msi_dup_property( package, property );
1680 if (!override)
1681 return FALSE;
1683 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1685 if (strcmpiW(override,all)==0)
1686 msi_feature_set_state( feature, state );
1687 else
1689 LPWSTR ptr = override;
1690 LPWSTR ptr2 = strchrW(override,',');
1692 while (ptr)
1694 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1695 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1697 msi_feature_set_state( feature, state );
1698 break;
1700 if (ptr2)
1702 ptr=ptr2+1;
1703 ptr2 = strchrW(ptr,',');
1705 else
1706 break;
1710 msi_free(override);
1712 return TRUE;
1715 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1717 int install_level;
1718 static const WCHAR szlevel[] =
1719 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1720 static const WCHAR szAddLocal[] =
1721 {'A','D','D','L','O','C','A','L',0};
1722 static const WCHAR szRemove[] =
1723 {'R','E','M','O','V','E',0};
1724 static const WCHAR szReinstall[] =
1725 {'R','E','I','N','S','T','A','L','L',0};
1726 BOOL override = FALSE;
1727 MSICOMPONENT* component;
1728 MSIFEATURE *feature;
1731 /* I do not know if this is where it should happen.. but */
1733 TRACE("Checking Install Level\n");
1735 install_level = msi_get_property_int( package, szlevel, 1 );
1737 /* ok here is the _real_ rub
1738 * all these activation/deactivation things happen in order and things
1739 * later on the list override things earlier on the list.
1740 * 1) INSTALLLEVEL processing
1741 * 2) ADDLOCAL
1742 * 3) REMOVE
1743 * 4) ADDSOURCE
1744 * 5) ADDDEFAULT
1745 * 6) REINSTALL
1746 * 7) COMPADDLOCAL
1747 * 8) COMPADDSOURCE
1748 * 9) FILEADDLOCAL
1749 * 10) FILEADDSOURCE
1750 * 11) FILEADDDEFAULT
1751 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1752 * ignored for all the features. seems strange, especially since it is not
1753 * documented anywhere, but it is how it works.
1755 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1756 * REMOVE are the big ones, since we don't handle administrative installs
1757 * yet anyway.
1759 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1760 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1761 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1763 if (!override)
1765 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1767 BOOL feature_state = ((feature->Level > 0) &&
1768 (feature->Level <= install_level));
1770 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1772 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1773 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1774 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1775 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1776 else
1777 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1781 /* disable child features of unselected parent features */
1782 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1784 FeatureList *fl;
1786 if (feature->Level > 0 && feature->Level <= install_level)
1787 continue;
1789 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1790 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1793 else
1795 /* set the Preselected Property */
1796 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1797 static const WCHAR szOne[] = { '1', 0 };
1799 MSI_SetPropertyW(package,szPreselected,szOne);
1803 * now we want to enable or disable components base on feature
1806 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1808 ComponentList *cl;
1810 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1811 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1813 /* features with components that have compressed files are made local */
1814 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1816 if (cl->component->Enabled &&
1817 cl->component->ForceLocalState &&
1818 feature->Action == INSTALLSTATE_SOURCE)
1820 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1821 break;
1825 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1827 component = cl->component;
1829 if (!component->Enabled)
1830 continue;
1832 switch (feature->Action)
1834 case INSTALLSTATE_ADVERTISED:
1835 component->hasAdvertiseFeature = 1;
1836 break;
1837 case INSTALLSTATE_SOURCE:
1838 component->hasSourceFeature = 1;
1839 break;
1840 case INSTALLSTATE_LOCAL:
1841 component->hasLocalFeature = 1;
1842 break;
1843 case INSTALLSTATE_DEFAULT:
1844 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1845 component->hasAdvertiseFeature = 1;
1846 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1847 component->hasSourceFeature = 1;
1848 else
1849 component->hasLocalFeature = 1;
1850 break;
1851 default:
1852 break;
1857 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1859 /* if the component isn't enabled, leave it alone */
1860 if (!component->Enabled)
1861 continue;
1863 /* check if it's local or source */
1864 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1865 (component->hasLocalFeature || component->hasSourceFeature))
1867 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1868 !component->ForceLocalState)
1869 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1870 else
1871 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1872 continue;
1875 /* if any feature is local, the component must be local too */
1876 if (component->hasLocalFeature)
1878 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1879 continue;
1882 if (component->hasSourceFeature)
1884 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1885 continue;
1888 if (component->hasAdvertiseFeature)
1890 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1891 continue;
1894 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1897 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1899 if (component->Action == INSTALLSTATE_DEFAULT)
1901 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1902 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1905 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1906 debugstr_w(component->Component), component->Installed, component->Action);
1910 return ERROR_SUCCESS;
1913 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1915 MSIPACKAGE *package = (MSIPACKAGE*)param;
1916 LPCWSTR name;
1917 LPWSTR path;
1918 MSIFOLDER *f;
1920 name = MSI_RecordGetString(row,1);
1922 f = get_loaded_folder(package, name);
1923 if (!f) return ERROR_SUCCESS;
1925 /* reset the ResolvedTarget */
1926 msi_free(f->ResolvedTarget);
1927 f->ResolvedTarget = NULL;
1929 /* This helper function now does ALL the work */
1930 TRACE("Dir %s ...\n",debugstr_w(name));
1931 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1932 TRACE("resolves to %s\n",debugstr_w(path));
1933 msi_free(path);
1935 return ERROR_SUCCESS;
1938 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1940 MSIPACKAGE *package = (MSIPACKAGE*)param;
1941 LPCWSTR name;
1942 MSIFEATURE *feature;
1944 name = MSI_RecordGetString( row, 1 );
1946 feature = get_loaded_feature( package, name );
1947 if (!feature)
1948 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1949 else
1951 LPCWSTR Condition;
1952 Condition = MSI_RecordGetString(row,3);
1954 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1956 int level = MSI_RecordGetInteger(row,2);
1957 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1958 feature->Level = level;
1961 return ERROR_SUCCESS;
1964 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1966 static const WCHAR name_fmt[] =
1967 {'%','u','.','%','u','.','%','u','.','%','u',0};
1968 static WCHAR name[] = {'\\',0};
1969 VS_FIXEDFILEINFO *lpVer;
1970 WCHAR filever[0x100];
1971 LPVOID version;
1972 DWORD versize;
1973 DWORD handle;
1974 UINT sz;
1976 TRACE("%s\n", debugstr_w(filename));
1978 versize = GetFileVersionInfoSizeW( filename, &handle );
1979 if (!versize)
1980 return NULL;
1982 version = msi_alloc( versize );
1983 GetFileVersionInfoW( filename, 0, versize, version );
1985 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1987 msi_free( version );
1988 return NULL;
1991 sprintfW( filever, name_fmt,
1992 HIWORD(lpVer->dwFileVersionMS),
1993 LOWORD(lpVer->dwFileVersionMS),
1994 HIWORD(lpVer->dwFileVersionLS),
1995 LOWORD(lpVer->dwFileVersionLS));
1997 msi_free( version );
1999 return strdupW( filever );
2002 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2004 LPWSTR file_version;
2005 MSIFILE *file;
2007 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2009 MSICOMPONENT* comp = file->Component;
2010 LPWSTR p;
2012 if (!comp)
2013 continue;
2015 if (file->IsCompressed)
2016 comp->ForceLocalState = TRUE;
2018 /* calculate target */
2019 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2021 msi_free(file->TargetPath);
2023 TRACE("file %s is named %s\n",
2024 debugstr_w(file->File), debugstr_w(file->FileName));
2026 file->TargetPath = build_directory_name(2, p, file->FileName);
2028 msi_free(p);
2030 TRACE("file %s resolves to %s\n",
2031 debugstr_w(file->File), debugstr_w(file->TargetPath));
2033 /* don't check files of components that aren't installed */
2034 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2035 comp->Installed == INSTALLSTATE_ABSENT)
2037 file->state = msifs_missing; /* assume files are missing */
2038 continue;
2041 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2043 file->state = msifs_missing;
2044 comp->Cost += file->FileSize;
2045 comp->Installed = INSTALLSTATE_INCOMPLETE;
2046 continue;
2049 if (file->Version &&
2050 (file_version = msi_get_disk_file_version( file->TargetPath )))
2052 TRACE("new %s old %s\n", debugstr_w(file->Version),
2053 debugstr_w(file_version));
2054 /* FIXME: seems like a bad way to compare version numbers */
2055 if (lstrcmpiW(file_version, file->Version)<0)
2057 file->state = msifs_overwrite;
2058 comp->Cost += file->FileSize;
2059 comp->Installed = INSTALLSTATE_INCOMPLETE;
2061 else
2062 file->state = msifs_present;
2063 msi_free( file_version );
2065 else
2066 file->state = msifs_present;
2069 return ERROR_SUCCESS;
2073 * A lot is done in this function aside from just the costing.
2074 * The costing needs to be implemented at some point but for now I am going
2075 * to focus on the directory building
2078 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2080 static const WCHAR ExecSeqQuery[] =
2081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2082 '`','D','i','r','e','c','t','o','r','y','`',0};
2083 static const WCHAR ConditionQuery[] =
2084 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2085 '`','C','o','n','d','i','t','i','o','n','`',0};
2086 static const WCHAR szCosting[] =
2087 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2088 static const WCHAR szlevel[] =
2089 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2090 static const WCHAR szOne[] = { '1', 0 };
2091 MSICOMPONENT *comp;
2092 UINT rc;
2093 MSIQUERY * view;
2094 LPWSTR level;
2096 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2097 return ERROR_SUCCESS;
2099 TRACE("Building Directory properties\n");
2101 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2102 if (rc == ERROR_SUCCESS)
2104 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2105 package);
2106 msiobj_release(&view->hdr);
2109 /* read components states from the registry */
2110 ACTION_GetComponentInstallStates(package);
2112 TRACE("File calculations\n");
2113 msi_check_file_install_states( package );
2115 TRACE("Evaluating Condition Table\n");
2117 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2118 if (rc == ERROR_SUCCESS)
2120 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2121 package);
2122 msiobj_release(&view->hdr);
2125 TRACE("Enabling or Disabling Components\n");
2126 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2128 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2130 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2131 comp->Enabled = FALSE;
2135 MSI_SetPropertyW(package,szCosting,szOne);
2136 /* set default run level if not set */
2137 level = msi_dup_property( package, szlevel );
2138 if (!level)
2139 MSI_SetPropertyW(package,szlevel, szOne);
2140 msi_free(level);
2142 ACTION_UpdateFeatureInstallStates(package);
2144 return MSI_SetFeatureStates(package);
2147 /* OK this value is "interpreted" and then formatted based on the
2148 first few characters */
2149 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2150 DWORD *size)
2152 LPSTR data = NULL;
2153 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2155 if (value[1]=='x')
2157 LPWSTR ptr;
2158 CHAR byte[5];
2159 LPWSTR deformated = NULL;
2160 int count;
2162 deformat_string(package, &value[2], &deformated);
2164 /* binary value type */
2165 ptr = deformated;
2166 *type = REG_BINARY;
2167 if (strlenW(ptr)%2)
2168 *size = (strlenW(ptr)/2)+1;
2169 else
2170 *size = strlenW(ptr)/2;
2172 data = msi_alloc(*size);
2174 byte[0] = '0';
2175 byte[1] = 'x';
2176 byte[4] = 0;
2177 count = 0;
2178 /* if uneven pad with a zero in front */
2179 if (strlenW(ptr)%2)
2181 byte[2]= '0';
2182 byte[3]= *ptr;
2183 ptr++;
2184 data[count] = (BYTE)strtol(byte,NULL,0);
2185 count ++;
2186 TRACE("Uneven byte count\n");
2188 while (*ptr)
2190 byte[2]= *ptr;
2191 ptr++;
2192 byte[3]= *ptr;
2193 ptr++;
2194 data[count] = (BYTE)strtol(byte,NULL,0);
2195 count ++;
2197 msi_free(deformated);
2199 TRACE("Data %i bytes(%i)\n",*size,count);
2201 else
2203 LPWSTR deformated;
2204 LPWSTR p;
2205 DWORD d = 0;
2206 deformat_string(package, &value[1], &deformated);
2208 *type=REG_DWORD;
2209 *size = sizeof(DWORD);
2210 data = msi_alloc(*size);
2211 p = deformated;
2212 if (*p == '-')
2213 p++;
2214 while (*p)
2216 if ( (*p < '0') || (*p > '9') )
2217 break;
2218 d *= 10;
2219 d += (*p - '0');
2220 p++;
2222 if (deformated[0] == '-')
2223 d = -d;
2224 *(LPDWORD)data = d;
2225 TRACE("DWORD %i\n",*(LPDWORD)data);
2227 msi_free(deformated);
2230 else
2232 static const WCHAR szMulti[] = {'[','~',']',0};
2233 LPCWSTR ptr;
2234 *type=REG_SZ;
2236 if (value[0]=='#')
2238 if (value[1]=='%')
2240 ptr = &value[2];
2241 *type=REG_EXPAND_SZ;
2243 else
2244 ptr = &value[1];
2246 else
2247 ptr=value;
2249 if (strstrW(value,szMulti))
2250 *type = REG_MULTI_SZ;
2252 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2254 return data;
2257 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2259 MSIPACKAGE *package = (MSIPACKAGE*)param;
2260 static const WCHAR szHCR[] =
2261 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2262 'R','O','O','T','\\',0};
2263 static const WCHAR szHCU[] =
2264 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2265 'U','S','E','R','\\',0};
2266 static const WCHAR szHLM[] =
2267 {'H','K','E','Y','_','L','O','C','A','L','_',
2268 'M','A','C','H','I','N','E','\\',0};
2269 static const WCHAR szHU[] =
2270 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2272 LPSTR value_data = NULL;
2273 HKEY root_key, hkey;
2274 DWORD type,size;
2275 LPWSTR deformated;
2276 LPCWSTR szRoot, component, name, key, value;
2277 MSICOMPONENT *comp;
2278 MSIRECORD * uirow;
2279 LPWSTR uikey;
2280 INT root;
2281 BOOL check_first = FALSE;
2282 UINT rc;
2284 ui_progress(package,2,0,0,0);
2286 value = NULL;
2287 key = NULL;
2288 uikey = NULL;
2289 name = NULL;
2291 component = MSI_RecordGetString(row, 6);
2292 comp = get_loaded_component(package,component);
2293 if (!comp)
2294 return ERROR_SUCCESS;
2296 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2298 TRACE("Skipping write due to disabled component %s\n",
2299 debugstr_w(component));
2301 comp->Action = comp->Installed;
2303 return ERROR_SUCCESS;
2306 comp->Action = INSTALLSTATE_LOCAL;
2308 name = MSI_RecordGetString(row, 4);
2309 if( MSI_RecordIsNull(row,5) && name )
2311 /* null values can have special meanings */
2312 if (name[0]=='-' && name[1] == 0)
2313 return ERROR_SUCCESS;
2314 else if ((name[0]=='+' && name[1] == 0) ||
2315 (name[0] == '*' && name[1] == 0))
2316 name = NULL;
2317 check_first = TRUE;
2320 root = MSI_RecordGetInteger(row,2);
2321 key = MSI_RecordGetString(row, 3);
2323 /* get the root key */
2324 switch (root)
2326 case -1:
2328 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2329 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2330 if (all_users && all_users[0] == '1')
2332 root_key = HKEY_LOCAL_MACHINE;
2333 szRoot = szHLM;
2335 else
2337 root_key = HKEY_CURRENT_USER;
2338 szRoot = szHCU;
2340 msi_free(all_users);
2342 break;
2343 case 0: root_key = HKEY_CLASSES_ROOT;
2344 szRoot = szHCR;
2345 break;
2346 case 1: root_key = HKEY_CURRENT_USER;
2347 szRoot = szHCU;
2348 break;
2349 case 2: root_key = HKEY_LOCAL_MACHINE;
2350 szRoot = szHLM;
2351 break;
2352 case 3: root_key = HKEY_USERS;
2353 szRoot = szHU;
2354 break;
2355 default:
2356 ERR("Unknown root %i\n",root);
2357 root_key=NULL;
2358 szRoot = NULL;
2359 break;
2361 if (!root_key)
2362 return ERROR_SUCCESS;
2364 deformat_string(package, key , &deformated);
2365 size = strlenW(deformated) + strlenW(szRoot) + 1;
2366 uikey = msi_alloc(size*sizeof(WCHAR));
2367 strcpyW(uikey,szRoot);
2368 strcatW(uikey,deformated);
2370 if (RegCreateKeyW( root_key, deformated, &hkey))
2372 ERR("Could not create key %s\n",debugstr_w(deformated));
2373 msi_free(deformated);
2374 msi_free(uikey);
2375 return ERROR_SUCCESS;
2377 msi_free(deformated);
2379 value = MSI_RecordGetString(row,5);
2380 if (value)
2381 value_data = parse_value(package, value, &type, &size);
2382 else
2384 static const WCHAR szEmpty[] = {0};
2385 value_data = (LPSTR)strdupW(szEmpty);
2386 size = 0;
2387 type = REG_SZ;
2390 deformat_string(package, name, &deformated);
2392 /* get the double nulls to terminate SZ_MULTI */
2393 if (type == REG_MULTI_SZ)
2394 size +=sizeof(WCHAR);
2396 if (!check_first)
2398 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2399 debugstr_w(uikey));
2400 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2402 else
2404 DWORD sz = 0;
2405 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2406 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2408 TRACE("value %s of %s checked already exists\n",
2409 debugstr_w(deformated), debugstr_w(uikey));
2411 else
2413 TRACE("Checked and setting value %s of %s\n",
2414 debugstr_w(deformated), debugstr_w(uikey));
2415 if (deformated || size)
2416 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2419 RegCloseKey(hkey);
2421 uirow = MSI_CreateRecord(3);
2422 MSI_RecordSetStringW(uirow,2,deformated);
2423 MSI_RecordSetStringW(uirow,1,uikey);
2425 if (type == REG_SZ)
2426 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2427 else
2428 MSI_RecordSetStringW(uirow,3,value);
2430 ui_actiondata(package,szWriteRegistryValues,uirow);
2431 msiobj_release( &uirow->hdr );
2433 msi_free(value_data);
2434 msi_free(deformated);
2435 msi_free(uikey);
2437 return ERROR_SUCCESS;
2440 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2442 UINT rc;
2443 MSIQUERY * view;
2444 static const WCHAR ExecSeqQuery[] =
2445 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2446 '`','R','e','g','i','s','t','r','y','`',0 };
2448 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2449 if (rc != ERROR_SUCCESS)
2450 return ERROR_SUCCESS;
2452 /* increment progress bar each time action data is sent */
2453 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2455 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2457 msiobj_release(&view->hdr);
2458 return rc;
2461 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2463 package->script->CurrentlyScripting = TRUE;
2465 return ERROR_SUCCESS;
2469 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2471 MSICOMPONENT *comp;
2472 DWORD progress = 0;
2473 DWORD total = 0;
2474 static const WCHAR q1[]=
2475 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2476 '`','R','e','g','i','s','t','r','y','`',0};
2477 UINT rc;
2478 MSIQUERY * view;
2479 MSIFEATURE *feature;
2480 MSIFILE *file;
2482 TRACE("InstallValidate\n");
2484 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2485 if (rc == ERROR_SUCCESS)
2487 MSI_IterateRecords( view, &progress, NULL, package );
2488 msiobj_release( &view->hdr );
2489 total += progress * REG_PROGRESS_VALUE;
2492 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2493 total += COMPONENT_PROGRESS_VALUE;
2495 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2496 total += file->FileSize;
2498 ui_progress(package,0,total,0,0);
2500 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2502 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2503 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2504 feature->ActionRequest);
2507 return ERROR_SUCCESS;
2510 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2512 MSIPACKAGE* package = (MSIPACKAGE*)param;
2513 LPCWSTR cond = NULL;
2514 LPCWSTR message = NULL;
2515 UINT r;
2517 static const WCHAR title[]=
2518 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2520 cond = MSI_RecordGetString(row,1);
2522 r = MSI_EvaluateConditionW(package,cond);
2523 if (r == MSICONDITION_FALSE)
2525 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2527 LPWSTR deformated;
2528 message = MSI_RecordGetString(row,2);
2529 deformat_string(package,message,&deformated);
2530 MessageBoxW(NULL,deformated,title,MB_OK);
2531 msi_free(deformated);
2534 return ERROR_INSTALL_FAILURE;
2537 return ERROR_SUCCESS;
2540 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2542 UINT rc;
2543 MSIQUERY * view = NULL;
2544 static const WCHAR ExecSeqQuery[] =
2545 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2546 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2548 TRACE("Checking launch conditions\n");
2550 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2551 if (rc != ERROR_SUCCESS)
2552 return ERROR_SUCCESS;
2554 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2555 msiobj_release(&view->hdr);
2557 return rc;
2560 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2563 if (!cmp->KeyPath)
2564 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2566 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2568 MSIRECORD * row = 0;
2569 UINT root,len;
2570 LPWSTR deformated,buffer,deformated_name;
2571 LPCWSTR key,name;
2572 static const WCHAR ExecSeqQuery[] =
2573 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2574 '`','R','e','g','i','s','t','r','y','`',' ',
2575 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2576 ' ','=',' ' ,'\'','%','s','\'',0 };
2577 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2578 static const WCHAR fmt2[]=
2579 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2581 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2582 if (!row)
2583 return NULL;
2585 root = MSI_RecordGetInteger(row,2);
2586 key = MSI_RecordGetString(row, 3);
2587 name = MSI_RecordGetString(row, 4);
2588 deformat_string(package, key , &deformated);
2589 deformat_string(package, name, &deformated_name);
2591 len = strlenW(deformated) + 6;
2592 if (deformated_name)
2593 len+=strlenW(deformated_name);
2595 buffer = msi_alloc( len *sizeof(WCHAR));
2597 if (deformated_name)
2598 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2599 else
2600 sprintfW(buffer,fmt,root,deformated);
2602 msi_free(deformated);
2603 msi_free(deformated_name);
2604 msiobj_release(&row->hdr);
2606 return buffer;
2608 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2610 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2611 return NULL;
2613 else
2615 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2617 if (file)
2618 return strdupW( file->TargetPath );
2620 return NULL;
2623 static HKEY openSharedDLLsKey(void)
2625 HKEY hkey=0;
2626 static const WCHAR path[] =
2627 {'S','o','f','t','w','a','r','e','\\',
2628 'M','i','c','r','o','s','o','f','t','\\',
2629 'W','i','n','d','o','w','s','\\',
2630 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2631 'S','h','a','r','e','d','D','L','L','s',0};
2633 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2634 return hkey;
2637 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2639 HKEY hkey;
2640 DWORD count=0;
2641 DWORD type;
2642 DWORD sz = sizeof(count);
2643 DWORD rc;
2645 hkey = openSharedDLLsKey();
2646 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2647 if (rc != ERROR_SUCCESS)
2648 count = 0;
2649 RegCloseKey(hkey);
2650 return count;
2653 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2655 HKEY hkey;
2657 hkey = openSharedDLLsKey();
2658 if (count > 0)
2659 msi_reg_set_val_dword( hkey, path, count );
2660 else
2661 RegDeleteValueW(hkey,path);
2662 RegCloseKey(hkey);
2663 return count;
2667 * Return TRUE if the count should be written out and FALSE if not
2669 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2671 MSIFEATURE *feature;
2672 INT count = 0;
2673 BOOL write = FALSE;
2675 /* only refcount DLLs */
2676 if (comp->KeyPath == NULL ||
2677 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2678 comp->Attributes & msidbComponentAttributesODBCDataSource)
2679 write = FALSE;
2680 else
2682 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2683 write = (count > 0);
2685 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2686 write = TRUE;
2689 /* increment counts */
2690 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2692 ComponentList *cl;
2694 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2695 continue;
2697 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2699 if ( cl->component == comp )
2700 count++;
2704 /* decrement counts */
2705 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2707 ComponentList *cl;
2709 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2710 continue;
2712 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2714 if ( cl->component == comp )
2715 count--;
2719 /* ref count all the files in the component */
2720 if (write)
2722 MSIFILE *file;
2724 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2726 if (file->Component == comp)
2727 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2731 /* add a count for permenent */
2732 if (comp->Attributes & msidbComponentAttributesPermanent)
2733 count ++;
2735 comp->RefCount = count;
2737 if (write)
2738 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2742 * Ok further analysis makes me think that this work is
2743 * actually done in the PublishComponents and PublishFeatures
2744 * step, and not here. It appears like the keypath and all that is
2745 * resolved in this step, however actually written in the Publish steps.
2746 * But we will leave it here for now because it is unclear
2748 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2750 WCHAR squished_pc[GUID_SIZE];
2751 WCHAR squished_cc[GUID_SIZE];
2752 UINT rc;
2753 MSICOMPONENT *comp;
2754 HKEY hkey=0,hkey2=0;
2756 /* writes the Component and Features values to the registry */
2758 rc = MSIREG_OpenComponents(&hkey);
2759 if (rc != ERROR_SUCCESS)
2760 return rc;
2762 squash_guid(package->ProductCode,squished_pc);
2763 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2765 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2767 MSIRECORD * uirow;
2769 ui_progress(package,2,0,0,0);
2770 if (!comp->ComponentId)
2771 continue;
2773 squash_guid(comp->ComponentId,squished_cc);
2775 msi_free(comp->FullKeypath);
2776 comp->FullKeypath = resolve_keypath( package, comp );
2778 /* do the refcounting */
2779 ACTION_RefCountComponent( package, comp );
2781 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2782 debugstr_w(comp->Component),
2783 debugstr_w(squished_cc),
2784 debugstr_w(comp->FullKeypath),
2785 comp->RefCount);
2787 * Write the keypath out if the component is to be registered
2788 * and delete the key if the component is to be deregistered
2790 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2792 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2793 if (rc != ERROR_SUCCESS)
2794 continue;
2796 if (!comp->FullKeypath)
2797 continue;
2799 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2801 if (comp->Attributes & msidbComponentAttributesPermanent)
2803 static const WCHAR szPermKey[] =
2804 { '0','0','0','0','0','0','0','0','0','0','0','0',
2805 '0','0','0','0','0','0','0','0','0','0','0','0',
2806 '0','0','0','0','0','0','0','0',0 };
2808 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2811 RegCloseKey(hkey2);
2813 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2815 DWORD res;
2817 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2818 if (rc != ERROR_SUCCESS)
2819 continue;
2821 RegDeleteValueW(hkey2,squished_pc);
2823 /* if the key is empty delete it */
2824 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2825 RegCloseKey(hkey2);
2826 if (res == ERROR_NO_MORE_ITEMS)
2827 RegDeleteKeyW(hkey,squished_cc);
2831 /* UI stuff */
2832 uirow = MSI_CreateRecord(3);
2833 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2834 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2835 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2836 ui_actiondata(package,szProcessComponents,uirow);
2837 msiobj_release( &uirow->hdr );
2839 RegCloseKey(hkey);
2840 return rc;
2843 typedef struct {
2844 CLSID clsid;
2845 LPWSTR source;
2847 LPWSTR path;
2848 ITypeLib *ptLib;
2849 } typelib_struct;
2851 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2852 LPWSTR lpszName, LONG_PTR lParam)
2854 TLIBATTR *attr;
2855 typelib_struct *tl_struct = (typelib_struct*) lParam;
2856 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2857 int sz;
2858 HRESULT res;
2860 if (!IS_INTRESOURCE(lpszName))
2862 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2863 return TRUE;
2866 sz = strlenW(tl_struct->source)+4;
2867 sz *= sizeof(WCHAR);
2869 if ((INT_PTR)lpszName == 1)
2870 tl_struct->path = strdupW(tl_struct->source);
2871 else
2873 tl_struct->path = msi_alloc(sz);
2874 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2877 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2878 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2879 if (!SUCCEEDED(res))
2881 msi_free(tl_struct->path);
2882 tl_struct->path = NULL;
2884 return TRUE;
2887 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2888 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2890 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2891 return FALSE;
2894 msi_free(tl_struct->path);
2895 tl_struct->path = NULL;
2897 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2898 ITypeLib_Release(tl_struct->ptLib);
2900 return TRUE;
2903 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2905 MSIPACKAGE* package = (MSIPACKAGE*)param;
2906 LPCWSTR component;
2907 MSICOMPONENT *comp;
2908 MSIFILE *file;
2909 typelib_struct tl_struct;
2910 HMODULE module;
2911 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2913 component = MSI_RecordGetString(row,3);
2914 comp = get_loaded_component(package,component);
2915 if (!comp)
2916 return ERROR_SUCCESS;
2918 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2920 TRACE("Skipping typelib reg due to disabled component\n");
2922 comp->Action = comp->Installed;
2924 return ERROR_SUCCESS;
2927 comp->Action = INSTALLSTATE_LOCAL;
2929 file = get_loaded_file( package, comp->KeyPath );
2930 if (!file)
2931 return ERROR_SUCCESS;
2933 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2934 if (module)
2936 LPCWSTR guid;
2937 guid = MSI_RecordGetString(row,1);
2938 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2939 tl_struct.source = strdupW( file->TargetPath );
2940 tl_struct.path = NULL;
2942 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2943 (LONG_PTR)&tl_struct);
2945 if (tl_struct.path)
2947 LPWSTR help = NULL;
2948 LPCWSTR helpid;
2949 HRESULT res;
2951 helpid = MSI_RecordGetString(row,6);
2953 if (helpid)
2954 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2955 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2956 msi_free(help);
2958 if (!SUCCEEDED(res))
2959 ERR("Failed to register type library %s\n",
2960 debugstr_w(tl_struct.path));
2961 else
2963 ui_actiondata(package,szRegisterTypeLibraries,row);
2965 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2968 ITypeLib_Release(tl_struct.ptLib);
2969 msi_free(tl_struct.path);
2971 else
2972 ERR("Failed to load type library %s\n",
2973 debugstr_w(tl_struct.source));
2975 FreeLibrary(module);
2976 msi_free(tl_struct.source);
2978 else
2979 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2981 return ERROR_SUCCESS;
2984 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2987 * OK this is a bit confusing.. I am given a _Component key and I believe
2988 * that the file that is being registered as a type library is the "key file
2989 * of that component" which I interpret to mean "The file in the KeyPath of
2990 * that component".
2992 UINT rc;
2993 MSIQUERY * view;
2994 static const WCHAR Query[] =
2995 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2996 '`','T','y','p','e','L','i','b','`',0};
2998 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2999 if (rc != ERROR_SUCCESS)
3000 return ERROR_SUCCESS;
3002 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3003 msiobj_release(&view->hdr);
3004 return rc;
3007 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3009 MSIPACKAGE *package = (MSIPACKAGE*)param;
3010 LPWSTR target_file, target_folder, filename;
3011 LPCWSTR buffer, extension;
3012 MSICOMPONENT *comp;
3013 static const WCHAR szlnk[]={'.','l','n','k',0};
3014 IShellLinkW *sl = NULL;
3015 IPersistFile *pf = NULL;
3016 HRESULT res;
3018 buffer = MSI_RecordGetString(row,4);
3019 comp = get_loaded_component(package,buffer);
3020 if (!comp)
3021 return ERROR_SUCCESS;
3023 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3025 TRACE("Skipping shortcut creation due to disabled component\n");
3027 comp->Action = comp->Installed;
3029 return ERROR_SUCCESS;
3032 comp->Action = INSTALLSTATE_LOCAL;
3034 ui_actiondata(package,szCreateShortcuts,row);
3036 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3037 &IID_IShellLinkW, (LPVOID *) &sl );
3039 if (FAILED( res ))
3041 ERR("CLSID_ShellLink not available\n");
3042 goto err;
3045 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3046 if (FAILED( res ))
3048 ERR("QueryInterface(IID_IPersistFile) failed\n");
3049 goto err;
3052 buffer = MSI_RecordGetString(row,2);
3053 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3055 /* may be needed because of a bug somehwere else */
3056 create_full_pathW(target_folder);
3058 filename = msi_dup_record_field( row, 3 );
3059 reduce_to_longfilename(filename);
3061 extension = strchrW(filename,'.');
3062 if (!extension || strcmpiW(extension,szlnk))
3064 int len = strlenW(filename);
3065 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3066 memcpy(filename + len, szlnk, sizeof(szlnk));
3068 target_file = build_directory_name(2, target_folder, filename);
3069 msi_free(target_folder);
3070 msi_free(filename);
3072 buffer = MSI_RecordGetString(row,5);
3073 if (strchrW(buffer,'['))
3075 LPWSTR deformated;
3076 deformat_string(package,buffer,&deformated);
3077 IShellLinkW_SetPath(sl,deformated);
3078 msi_free(deformated);
3080 else
3082 FIXME("poorly handled shortcut format, advertised shortcut\n");
3083 IShellLinkW_SetPath(sl,comp->FullKeypath);
3086 if (!MSI_RecordIsNull(row,6))
3088 LPWSTR deformated;
3089 buffer = MSI_RecordGetString(row,6);
3090 deformat_string(package,buffer,&deformated);
3091 IShellLinkW_SetArguments(sl,deformated);
3092 msi_free(deformated);
3095 if (!MSI_RecordIsNull(row,7))
3097 buffer = MSI_RecordGetString(row,7);
3098 IShellLinkW_SetDescription(sl,buffer);
3101 if (!MSI_RecordIsNull(row,8))
3102 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3104 if (!MSI_RecordIsNull(row,9))
3106 LPWSTR Path;
3107 INT index;
3109 buffer = MSI_RecordGetString(row,9);
3111 Path = build_icon_path(package,buffer);
3112 index = MSI_RecordGetInteger(row,10);
3114 /* no value means 0 */
3115 if (index == MSI_NULL_INTEGER)
3116 index = 0;
3118 IShellLinkW_SetIconLocation(sl,Path,index);
3119 msi_free(Path);
3122 if (!MSI_RecordIsNull(row,11))
3123 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3125 if (!MSI_RecordIsNull(row,12))
3127 LPWSTR Path;
3128 buffer = MSI_RecordGetString(row,12);
3129 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3130 if (Path)
3131 IShellLinkW_SetWorkingDirectory(sl,Path);
3132 msi_free(Path);
3135 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3136 IPersistFile_Save(pf,target_file,FALSE);
3138 msi_free(target_file);
3140 err:
3141 if (pf)
3142 IPersistFile_Release( pf );
3143 if (sl)
3144 IShellLinkW_Release( sl );
3146 return ERROR_SUCCESS;
3149 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3151 UINT rc;
3152 HRESULT res;
3153 MSIQUERY * view;
3154 static const WCHAR Query[] =
3155 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3156 '`','S','h','o','r','t','c','u','t','`',0};
3158 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3159 if (rc != ERROR_SUCCESS)
3160 return ERROR_SUCCESS;
3162 res = CoInitialize( NULL );
3163 if (FAILED (res))
3165 ERR("CoInitialize failed\n");
3166 return ERROR_FUNCTION_FAILED;
3169 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3170 msiobj_release(&view->hdr);
3172 CoUninitialize();
3174 return rc;
3177 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3179 MSIPACKAGE* package = (MSIPACKAGE*)param;
3180 HANDLE the_file;
3181 LPWSTR FilePath;
3182 LPCWSTR FileName;
3183 CHAR buffer[1024];
3184 DWORD sz;
3185 UINT rc;
3186 MSIRECORD *uirow;
3188 FileName = MSI_RecordGetString(row,1);
3189 if (!FileName)
3191 ERR("Unable to get FileName\n");
3192 return ERROR_SUCCESS;
3195 FilePath = build_icon_path(package,FileName);
3197 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3199 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3200 FILE_ATTRIBUTE_NORMAL, NULL);
3202 if (the_file == INVALID_HANDLE_VALUE)
3204 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3205 msi_free(FilePath);
3206 return ERROR_SUCCESS;
3211 DWORD write;
3212 sz = 1024;
3213 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3214 if (rc != ERROR_SUCCESS)
3216 ERR("Failed to get stream\n");
3217 CloseHandle(the_file);
3218 DeleteFileW(FilePath);
3219 break;
3221 WriteFile(the_file,buffer,sz,&write,NULL);
3222 } while (sz == 1024);
3224 msi_free(FilePath);
3226 CloseHandle(the_file);
3228 uirow = MSI_CreateRecord(1);
3229 MSI_RecordSetStringW(uirow,1,FileName);
3230 ui_actiondata(package,szPublishProduct,uirow);
3231 msiobj_release( &uirow->hdr );
3233 return ERROR_SUCCESS;
3237 * 99% of the work done here is only done for
3238 * advertised installs. However this is where the
3239 * Icon table is processed and written out
3240 * so that is what I am going to do here.
3242 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3244 UINT rc;
3245 MSIQUERY * view;
3246 static const WCHAR Query[]=
3247 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3248 '`','I','c','o','n','`',0};
3249 /* for registry stuff */
3250 HKEY hkey=0;
3251 HKEY hukey=0;
3252 HKEY hudkey=0, props=0;
3253 static const WCHAR szProductLanguage[] =
3254 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3255 static const WCHAR szARPProductIcon[] =
3256 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3257 static const WCHAR szProductVersion[] =
3258 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3259 static const WCHAR szInstallProperties[] =
3260 {'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
3261 static const WCHAR szWindowsInstaller[] =
3262 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3263 DWORD langid;
3264 LPWSTR buffer;
3265 DWORD size;
3266 MSIHANDLE hDb, hSumInfo;
3268 /* write out icon files */
3270 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3271 if (rc == ERROR_SUCCESS)
3273 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3274 msiobj_release(&view->hdr);
3277 /* ok there is a lot more done here but i need to figure out what */
3279 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3280 if (rc != ERROR_SUCCESS)
3281 goto end;
3283 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3284 if (rc != ERROR_SUCCESS)
3285 goto end;
3287 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3288 if (rc != ERROR_SUCCESS)
3289 goto end;
3291 rc = RegCreateKeyW(hudkey, szInstallProperties, &props);
3292 if (rc != ERROR_SUCCESS)
3293 goto end;
3295 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
3297 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3298 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3299 msi_free(buffer);
3301 langid = msi_get_property_int( package, szProductLanguage, 0 );
3302 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3304 buffer = msi_dup_property( package, szARPProductIcon );
3305 if (buffer)
3307 LPWSTR path = build_icon_path(package,buffer);
3308 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3309 msi_free( path );
3311 msi_free(buffer);
3313 buffer = msi_dup_property( package, szProductVersion );
3314 if (buffer)
3316 DWORD verdword = msi_version_str_to_dword(buffer);
3317 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3319 msi_free(buffer);
3321 /* FIXME: Need to write more keys to the user registry */
3323 hDb= alloc_msihandle( &package->db->hdr );
3324 if (!hDb) {
3325 rc = ERROR_NOT_ENOUGH_MEMORY;
3326 goto end;
3328 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3329 MsiCloseHandle(hDb);
3330 if (rc == ERROR_SUCCESS)
3332 WCHAR guidbuffer[0x200];
3333 size = 0x200;
3334 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3335 guidbuffer, &size);
3336 if (rc == ERROR_SUCCESS)
3338 WCHAR squashed[GUID_SIZE];
3339 /* for now we only care about the first guid */
3340 LPWSTR ptr = strchrW(guidbuffer,';');
3341 if (ptr) *ptr = 0;
3342 squash_guid(guidbuffer,squashed);
3343 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3345 else
3347 ERR("Unable to query Revision_Number...\n");
3348 rc = ERROR_SUCCESS;
3350 MsiCloseHandle(hSumInfo);
3352 else
3354 ERR("Unable to open Summary Information\n");
3355 rc = ERROR_SUCCESS;
3358 end:
3359 RegCloseKey(hkey);
3360 RegCloseKey(hukey);
3361 RegCloseKey(hudkey);
3362 RegCloseKey(props);
3364 return rc;
3367 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3369 MSIPACKAGE *package = (MSIPACKAGE*)param;
3370 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3371 LPWSTR deformated_section, deformated_key, deformated_value;
3372 LPWSTR folder, fullname = NULL;
3373 MSIRECORD * uirow;
3374 INT action;
3375 MSICOMPONENT *comp;
3376 static const WCHAR szWindowsFolder[] =
3377 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3379 component = MSI_RecordGetString(row, 8);
3380 comp = get_loaded_component(package,component);
3382 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3384 TRACE("Skipping ini file due to disabled component %s\n",
3385 debugstr_w(component));
3387 comp->Action = comp->Installed;
3389 return ERROR_SUCCESS;
3392 comp->Action = INSTALLSTATE_LOCAL;
3394 identifier = MSI_RecordGetString(row,1);
3395 filename = MSI_RecordGetString(row,2);
3396 dirproperty = MSI_RecordGetString(row,3);
3397 section = MSI_RecordGetString(row,4);
3398 key = MSI_RecordGetString(row,5);
3399 value = MSI_RecordGetString(row,6);
3400 action = MSI_RecordGetInteger(row,7);
3402 deformat_string(package,section,&deformated_section);
3403 deformat_string(package,key,&deformated_key);
3404 deformat_string(package,value,&deformated_value);
3406 if (dirproperty)
3408 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3409 if (!folder)
3410 folder = msi_dup_property( package, dirproperty );
3412 else
3413 folder = msi_dup_property( package, szWindowsFolder );
3415 if (!folder)
3417 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3418 goto cleanup;
3421 fullname = build_directory_name(2, folder, filename);
3423 if (action == 0)
3425 TRACE("Adding value %s to section %s in %s\n",
3426 debugstr_w(deformated_key), debugstr_w(deformated_section),
3427 debugstr_w(fullname));
3428 WritePrivateProfileStringW(deformated_section, deformated_key,
3429 deformated_value, fullname);
3431 else if (action == 1)
3433 WCHAR returned[10];
3434 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3435 returned, 10, fullname);
3436 if (returned[0] == 0)
3438 TRACE("Adding value %s to section %s in %s\n",
3439 debugstr_w(deformated_key), debugstr_w(deformated_section),
3440 debugstr_w(fullname));
3442 WritePrivateProfileStringW(deformated_section, deformated_key,
3443 deformated_value, fullname);
3446 else if (action == 3)
3447 FIXME("Append to existing section not yet implemented\n");
3449 uirow = MSI_CreateRecord(4);
3450 MSI_RecordSetStringW(uirow,1,identifier);
3451 MSI_RecordSetStringW(uirow,2,deformated_section);
3452 MSI_RecordSetStringW(uirow,3,deformated_key);
3453 MSI_RecordSetStringW(uirow,4,deformated_value);
3454 ui_actiondata(package,szWriteIniValues,uirow);
3455 msiobj_release( &uirow->hdr );
3456 cleanup:
3457 msi_free(fullname);
3458 msi_free(folder);
3459 msi_free(deformated_key);
3460 msi_free(deformated_value);
3461 msi_free(deformated_section);
3462 return ERROR_SUCCESS;
3465 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3467 UINT rc;
3468 MSIQUERY * view;
3469 static const WCHAR ExecSeqQuery[] =
3470 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3471 '`','I','n','i','F','i','l','e','`',0};
3473 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3474 if (rc != ERROR_SUCCESS)
3476 TRACE("no IniFile table\n");
3477 return ERROR_SUCCESS;
3480 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3481 msiobj_release(&view->hdr);
3482 return rc;
3485 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3487 MSIPACKAGE *package = (MSIPACKAGE*)param;
3488 LPCWSTR filename;
3489 LPWSTR FullName;
3490 MSIFILE *file;
3491 DWORD len;
3492 static const WCHAR ExeStr[] =
3493 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3494 static const WCHAR close[] = {'\"',0};
3495 STARTUPINFOW si;
3496 PROCESS_INFORMATION info;
3497 BOOL brc;
3498 MSIRECORD *uirow;
3499 LPWSTR uipath, p;
3501 memset(&si,0,sizeof(STARTUPINFOW));
3503 filename = MSI_RecordGetString(row,1);
3504 file = get_loaded_file( package, filename );
3506 if (!file)
3508 ERR("Unable to find file id %s\n",debugstr_w(filename));
3509 return ERROR_SUCCESS;
3512 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3514 FullName = msi_alloc(len*sizeof(WCHAR));
3515 strcpyW(FullName,ExeStr);
3516 strcatW( FullName, file->TargetPath );
3517 strcatW(FullName,close);
3519 TRACE("Registering %s\n",debugstr_w(FullName));
3520 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3521 &si, &info);
3523 if (brc)
3524 msi_dialog_check_messages(info.hProcess);
3526 msi_free(FullName);
3528 /* the UI chunk */
3529 uirow = MSI_CreateRecord( 2 );
3530 uipath = strdupW( file->TargetPath );
3531 p = strrchrW(uipath,'\\');
3532 if (p)
3533 p[0]=0;
3534 MSI_RecordSetStringW( uirow, 1, &p[1] );
3535 MSI_RecordSetStringW( uirow, 2, uipath);
3536 ui_actiondata( package, szSelfRegModules, uirow);
3537 msiobj_release( &uirow->hdr );
3538 msi_free( uipath );
3539 /* FIXME: call ui_progress? */
3541 return ERROR_SUCCESS;
3544 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3546 UINT rc;
3547 MSIQUERY * view;
3548 static const WCHAR ExecSeqQuery[] =
3549 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3550 '`','S','e','l','f','R','e','g','`',0};
3552 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3553 if (rc != ERROR_SUCCESS)
3555 TRACE("no SelfReg table\n");
3556 return ERROR_SUCCESS;
3559 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3560 msiobj_release(&view->hdr);
3562 return ERROR_SUCCESS;
3565 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3567 MSIFEATURE *feature;
3568 UINT rc;
3569 HKEY hkey=0;
3570 HKEY hukey=0;
3572 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3573 if (rc != ERROR_SUCCESS)
3574 goto end;
3576 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3577 if (rc != ERROR_SUCCESS)
3578 goto end;
3580 /* here the guids are base 85 encoded */
3581 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3583 ComponentList *cl;
3584 LPWSTR data = NULL;
3585 GUID clsid;
3586 INT size;
3587 BOOL absent = FALSE;
3588 MSIRECORD *uirow;
3590 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3591 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3592 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3593 absent = TRUE;
3595 size = 1;
3596 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3598 size += 21;
3600 if (feature->Feature_Parent)
3601 size += strlenW( feature->Feature_Parent )+2;
3603 data = msi_alloc(size * sizeof(WCHAR));
3605 data[0] = 0;
3606 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3608 MSICOMPONENT* component = cl->component;
3609 WCHAR buf[21];
3611 buf[0] = 0;
3612 if (component->ComponentId)
3614 TRACE("From %s\n",debugstr_w(component->ComponentId));
3615 CLSIDFromString(component->ComponentId, &clsid);
3616 encode_base85_guid(&clsid,buf);
3617 TRACE("to %s\n",debugstr_w(buf));
3618 strcatW(data,buf);
3621 if (feature->Feature_Parent)
3623 static const WCHAR sep[] = {'\2',0};
3624 strcatW(data,sep);
3625 strcatW(data,feature->Feature_Parent);
3628 msi_reg_set_val_str( hkey, feature->Feature, data );
3629 msi_free(data);
3631 size = 0;
3632 if (feature->Feature_Parent)
3633 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3634 if (!absent)
3636 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3637 (LPBYTE)feature->Feature_Parent,size);
3639 else
3641 size += 2*sizeof(WCHAR);
3642 data = msi_alloc(size);
3643 data[0] = 0x6;
3644 data[1] = 0;
3645 if (feature->Feature_Parent)
3646 strcpyW( &data[1], feature->Feature_Parent );
3647 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3648 (LPBYTE)data,size);
3649 msi_free(data);
3652 /* the UI chunk */
3653 uirow = MSI_CreateRecord( 1 );
3654 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3655 ui_actiondata( package, szPublishFeatures, uirow);
3656 msiobj_release( &uirow->hdr );
3657 /* FIXME: call ui_progress? */
3660 end:
3661 RegCloseKey(hkey);
3662 RegCloseKey(hukey);
3663 return rc;
3666 static UINT msi_get_local_package_name( LPWSTR path )
3668 static const WCHAR szInstaller[] = {
3669 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3670 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3671 DWORD time, len, i;
3672 HANDLE handle;
3674 time = GetTickCount();
3675 GetWindowsDirectoryW( path, MAX_PATH );
3676 lstrcatW( path, szInstaller );
3677 CreateDirectoryW( path, NULL );
3679 len = lstrlenW(path);
3680 for (i=0; i<0x10000; i++)
3682 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3683 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3684 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3685 if (handle != INVALID_HANDLE_VALUE)
3687 CloseHandle(handle);
3688 break;
3690 if (GetLastError() != ERROR_FILE_EXISTS &&
3691 GetLastError() != ERROR_SHARING_VIOLATION)
3692 return ERROR_FUNCTION_FAILED;
3695 return ERROR_SUCCESS;
3698 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3700 static const WCHAR szOriginalDatabase[] =
3701 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3702 WCHAR packagefile[MAX_PATH];
3703 LPWSTR msiFilePath;
3704 UINT r;
3706 r = msi_get_local_package_name( packagefile );
3707 if (r != ERROR_SUCCESS)
3708 return r;
3710 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3712 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3713 r = CopyFileW( msiFilePath, packagefile, FALSE);
3715 if (!r)
3717 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3718 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3719 msi_free( msiFilePath );
3720 return ERROR_FUNCTION_FAILED;
3722 msi_free( msiFilePath );
3724 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3725 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3726 return ERROR_SUCCESS;
3729 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3731 LPWSTR prop, val, key;
3732 static const LPCSTR propval[] = {
3733 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3734 "ARPCONTACT", "Contact",
3735 "ARPCOMMENTS", "Comments",
3736 "ProductName", "DisplayName",
3737 "ProductVersion", "DisplayVersion",
3738 "ARPHELPLINK", "HelpLink",
3739 "ARPHELPTELEPHONE", "HelpTelephone",
3740 "ARPINSTALLLOCATION", "InstallLocation",
3741 "SourceDir", "InstallSource",
3742 "Manufacturer", "Publisher",
3743 "ARPREADME", "Readme",
3744 "ARPSIZE", "Size",
3745 "ARPURLINFOABOUT", "URLInfoAbout",
3746 "ARPURLUPDATEINFO", "URLUpdateInfo",
3747 NULL,
3749 const LPCSTR *p = propval;
3751 while( *p )
3753 prop = strdupAtoW( *p++ );
3754 key = strdupAtoW( *p++ );
3755 val = msi_dup_property( package, prop );
3756 msi_reg_set_val_str( hkey, key, val );
3757 msi_free(val);
3758 msi_free(key);
3759 msi_free(prop);
3761 return ERROR_SUCCESS;
3764 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3766 HKEY hkey=0;
3767 LPWSTR buffer = NULL;
3768 UINT rc;
3769 DWORD size, langid;
3770 static const WCHAR szWindowsInstaller[] =
3771 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3772 static const WCHAR szUpgradeCode[] =
3773 {'U','p','g','r','a','d','e','C','o','d','e',0};
3774 static const WCHAR modpath_fmt[] =
3775 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3776 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3777 static const WCHAR szModifyPath[] =
3778 {'M','o','d','i','f','y','P','a','t','h',0};
3779 static const WCHAR szUninstallString[] =
3780 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3781 static const WCHAR szEstimatedSize[] =
3782 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3783 static const WCHAR szProductLanguage[] =
3784 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3785 static const WCHAR szProductVersion[] =
3786 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3788 SYSTEMTIME systime;
3789 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3790 LPWSTR upgrade_code;
3791 WCHAR szDate[9];
3793 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3794 if (rc != ERROR_SUCCESS)
3795 return rc;
3797 /* dump all the info i can grab */
3798 /* FIXME: Flesh out more information */
3800 msi_write_uninstall_property_vals( package, hkey );
3802 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3804 msi_make_package_local( package, hkey );
3806 /* do ModifyPath and UninstallString */
3807 size = deformat_string(package,modpath_fmt,&buffer);
3808 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3809 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3810 msi_free(buffer);
3812 /* FIXME: Write real Estimated Size when we have it */
3813 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3815 GetLocalTime(&systime);
3816 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3817 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3819 langid = msi_get_property_int( package, szProductLanguage, 0 );
3820 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3822 buffer = msi_dup_property( package, szProductVersion );
3823 if (buffer)
3825 DWORD verdword = msi_version_str_to_dword(buffer);
3827 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3828 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3829 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3831 msi_free(buffer);
3833 /* Handle Upgrade Codes */
3834 upgrade_code = msi_dup_property( package, szUpgradeCode );
3835 if (upgrade_code)
3837 HKEY hkey2;
3838 WCHAR squashed[33];
3839 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3840 squash_guid(package->ProductCode,squashed);
3841 msi_reg_set_val_str( hkey2, squashed, NULL );
3842 RegCloseKey(hkey2);
3843 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3844 squash_guid(package->ProductCode,squashed);
3845 msi_reg_set_val_str( hkey2, squashed, NULL );
3846 RegCloseKey(hkey2);
3848 msi_free(upgrade_code);
3851 RegCloseKey(hkey);
3853 /* FIXME: call ui_actiondata */
3855 return ERROR_SUCCESS;
3858 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3860 return execute_script(package,INSTALL_SCRIPT);
3863 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3865 UINT rc;
3867 /* turn off scheduling */
3868 package->script->CurrentlyScripting= FALSE;
3870 /* first do the same as an InstallExecute */
3871 rc = ACTION_InstallExecute(package);
3872 if (rc != ERROR_SUCCESS)
3873 return rc;
3875 /* then handle Commit Actions */
3876 rc = execute_script(package,COMMIT_SCRIPT);
3878 return rc;
3881 UINT ACTION_ForceReboot(MSIPACKAGE *package)
3883 static const WCHAR RunOnce[] = {
3884 'S','o','f','t','w','a','r','e','\\',
3885 'M','i','c','r','o','s','o','f','t','\\',
3886 'W','i','n','d','o','w','s','\\',
3887 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3888 'R','u','n','O','n','c','e',0};
3889 static const WCHAR InstallRunOnce[] = {
3890 'S','o','f','t','w','a','r','e','\\',
3891 'M','i','c','r','o','s','o','f','t','\\',
3892 'W','i','n','d','o','w','s','\\',
3893 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3894 'I','n','s','t','a','l','l','e','r','\\',
3895 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3897 static const WCHAR msiexec_fmt[] = {
3898 '%','s',
3899 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3900 '\"','%','s','\"',0};
3901 static const WCHAR install_fmt[] = {
3902 '/','I',' ','\"','%','s','\"',' ',
3903 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3904 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3905 WCHAR buffer[256], sysdir[MAX_PATH];
3906 HKEY hkey;
3907 WCHAR squished_pc[100];
3909 squash_guid(package->ProductCode,squished_pc);
3911 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3912 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3913 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3914 squished_pc);
3916 msi_reg_set_val_str( hkey, squished_pc, buffer );
3917 RegCloseKey(hkey);
3919 TRACE("Reboot command %s\n",debugstr_w(buffer));
3921 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3922 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3924 msi_reg_set_val_str( hkey, squished_pc, buffer );
3925 RegCloseKey(hkey);
3927 return ERROR_INSTALL_SUSPEND;
3930 static UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3932 LPWSTR p, source;
3933 DWORD len;
3935 p = strrchrW( package->PackagePath, '\\' );
3936 if (!p)
3937 return ERROR_SUCCESS;
3939 len = p - package->PackagePath + 2;
3940 source = msi_alloc( len * sizeof(WCHAR) );
3941 lstrcpynW( source, package->PackagePath, len );
3943 MSI_SetPropertyW( package, cszSourceDir, source );
3944 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3946 msi_free( source );
3948 return ERROR_SUCCESS;
3951 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3953 DWORD attrib;
3954 UINT rc;
3957 * We are currently doing what should be done here in the top level Install
3958 * however for Administrative and uninstalls this step will be needed
3960 if (!package->PackagePath)
3961 return ERROR_SUCCESS;
3963 msi_set_sourcedir_props(package);
3965 attrib = GetFileAttributesW(package->PackagePath);
3966 if (attrib == INVALID_FILE_ATTRIBUTES)
3968 LPWSTR prompt;
3969 LPWSTR msg;
3970 DWORD size = 0;
3972 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3973 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3974 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3975 if (rc == ERROR_MORE_DATA)
3977 prompt = msi_alloc(size * sizeof(WCHAR));
3978 MsiSourceListGetInfoW(package->ProductCode, NULL,
3979 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3980 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3982 else
3983 prompt = strdupW(package->PackagePath);
3985 msg = generate_error_string(package,1302,1,prompt);
3986 while(attrib == INVALID_FILE_ATTRIBUTES)
3988 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3989 if (rc == IDCANCEL)
3991 rc = ERROR_INSTALL_USEREXIT;
3992 break;
3994 attrib = GetFileAttributesW(package->PackagePath);
3996 msi_free(prompt);
3997 rc = ERROR_SUCCESS;
3999 else
4000 return ERROR_SUCCESS;
4002 return rc;
4005 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4007 HKEY hkey=0;
4008 LPWSTR buffer;
4009 LPWSTR productid;
4010 UINT rc,i;
4012 static const WCHAR szPropKeys[][80] =
4014 {'P','r','o','d','u','c','t','I','D',0},
4015 {'U','S','E','R','N','A','M','E',0},
4016 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4017 {0},
4020 static const WCHAR szRegKeys[][80] =
4022 {'P','r','o','d','u','c','t','I','D',0},
4023 {'R','e','g','O','w','n','e','r',0},
4024 {'R','e','g','C','o','m','p','a','n','y',0},
4025 {0},
4028 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4029 if (!productid)
4030 return ERROR_SUCCESS;
4032 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
4033 if (rc != ERROR_SUCCESS)
4034 goto end;
4036 for( i = 0; szPropKeys[i][0]; i++ )
4038 buffer = msi_dup_property( package, szPropKeys[i] );
4039 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4040 msi_free( buffer );
4043 end:
4044 msi_free(productid);
4045 RegCloseKey(hkey);
4047 /* FIXME: call ui_actiondata */
4049 return ERROR_SUCCESS;
4053 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4055 UINT rc;
4057 package->script->InWhatSequence |= SEQUENCE_EXEC;
4058 rc = ACTION_ProcessExecSequence(package,FALSE);
4059 return rc;
4063 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4065 MSIPACKAGE *package = (MSIPACKAGE*)param;
4066 LPCWSTR compgroupid=NULL;
4067 LPCWSTR feature=NULL;
4068 LPCWSTR text = NULL;
4069 LPCWSTR qualifier = NULL;
4070 LPCWSTR component = NULL;
4071 LPWSTR advertise = NULL;
4072 LPWSTR output = NULL;
4073 HKEY hkey;
4074 UINT rc = ERROR_SUCCESS;
4075 MSICOMPONENT *comp;
4076 DWORD sz = 0;
4077 MSIRECORD *uirow;
4079 component = MSI_RecordGetString(rec,3);
4080 comp = get_loaded_component(package,component);
4082 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4083 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4084 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4086 TRACE("Skipping: Component %s not scheduled for install\n",
4087 debugstr_w(component));
4089 return ERROR_SUCCESS;
4092 compgroupid = MSI_RecordGetString(rec,1);
4093 qualifier = MSI_RecordGetString(rec,2);
4095 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4096 if (rc != ERROR_SUCCESS)
4097 goto end;
4099 text = MSI_RecordGetString(rec,4);
4100 feature = MSI_RecordGetString(rec,5);
4102 advertise = create_component_advertise_string(package, comp, feature);
4104 sz = strlenW(advertise);
4106 if (text)
4107 sz += lstrlenW(text);
4109 sz+=3;
4110 sz *= sizeof(WCHAR);
4112 output = msi_alloc_zero(sz);
4113 strcpyW(output,advertise);
4114 msi_free(advertise);
4116 if (text)
4117 strcatW(output,text);
4119 msi_reg_set_val_multi_str( hkey, qualifier, output );
4121 end:
4122 RegCloseKey(hkey);
4123 msi_free(output);
4125 /* the UI chunk */
4126 uirow = MSI_CreateRecord( 2 );
4127 MSI_RecordSetStringW( uirow, 1, compgroupid );
4128 MSI_RecordSetStringW( uirow, 2, qualifier);
4129 ui_actiondata( package, szPublishComponents, uirow);
4130 msiobj_release( &uirow->hdr );
4131 /* FIXME: call ui_progress? */
4133 return rc;
4137 * At present I am ignorning the advertised components part of this and only
4138 * focusing on the qualified component sets
4140 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4142 UINT rc;
4143 MSIQUERY * view;
4144 static const WCHAR ExecSeqQuery[] =
4145 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4146 '`','P','u','b','l','i','s','h',
4147 'C','o','m','p','o','n','e','n','t','`',0};
4149 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4150 if (rc != ERROR_SUCCESS)
4151 return ERROR_SUCCESS;
4153 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4154 msiobj_release(&view->hdr);
4156 return rc;
4159 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4161 MSIPACKAGE *package = (MSIPACKAGE*)param;
4162 MSIRECORD *row;
4163 MSIFILE *file;
4164 SC_HANDLE hscm, service = NULL;
4165 LPCWSTR name, disp, comp, depends, pass;
4166 LPCWSTR load_order, serv_name, key;
4167 DWORD serv_type, start_type;
4168 DWORD err_control;
4170 static const WCHAR query[] =
4171 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4172 '`','C','o','m','p','o','n','e','n','t','`',' ',
4173 'W','H','E','R','E',' ',
4174 '`','C','o','m','p','o','n','e','n','t','`',' ',
4175 '=','\'','%','s','\'',0};
4177 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4178 if (!hscm)
4180 ERR("Failed to open the SC Manager!\n");
4181 goto done;
4184 start_type = MSI_RecordGetInteger(rec, 5);
4185 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4186 goto done;
4188 depends = MSI_RecordGetString(rec, 8);
4189 if (depends && *depends)
4190 FIXME("Dependency list unhandled!\n");
4192 name = MSI_RecordGetString(rec, 2);
4193 disp = MSI_RecordGetString(rec, 3);
4194 serv_type = MSI_RecordGetInteger(rec, 4);
4195 err_control = MSI_RecordGetInteger(rec, 6);
4196 load_order = MSI_RecordGetString(rec, 7);
4197 serv_name = MSI_RecordGetString(rec, 9);
4198 pass = MSI_RecordGetString(rec, 10);
4199 comp = MSI_RecordGetString(rec, 12);
4201 /* fetch the service path */
4202 row = MSI_QueryGetRecord(package->db, query, comp);
4203 if (!row)
4205 ERR("Control query failed!\n");
4206 goto done;
4209 key = MSI_RecordGetString(row, 6);
4210 msiobj_release(&row->hdr);
4212 file = get_loaded_file(package, key);
4213 if (!file)
4215 ERR("Failed to load the service file\n");
4216 goto done;
4219 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4220 start_type, err_control, file->TargetPath,
4221 load_order, NULL, NULL, serv_name, pass);
4222 if (!service)
4224 if (GetLastError() != ERROR_SERVICE_EXISTS)
4225 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4228 done:
4229 CloseServiceHandle(service);
4230 CloseServiceHandle(hscm);
4232 return ERROR_SUCCESS;
4235 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4237 UINT rc;
4238 MSIQUERY * view;
4239 static const WCHAR ExecSeqQuery[] =
4240 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4241 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4243 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4244 if (rc != ERROR_SUCCESS)
4245 return ERROR_SUCCESS;
4247 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4248 msiobj_release(&view->hdr);
4250 return rc;
4253 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4254 static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs)
4256 LPCWSTR *vector;
4257 LPWSTR p, q;
4258 DWORD sep_len;
4260 static const WCHAR separator[] = {'[','~',']',0};
4262 *numargs = 0;
4263 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4265 if (!args)
4266 return NULL;
4268 vector = msi_alloc(sizeof(LPWSTR));
4269 if (!vector)
4270 return NULL;
4272 p = args;
4275 (*numargs)++;
4276 vector[*numargs - 1] = p;
4278 if ((q = strstrW(p, separator)))
4280 *q = '\0';
4282 vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4283 if (!vector)
4284 return NULL;
4286 p = q + sep_len;
4288 } while (q);
4290 return vector;
4293 static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component )
4295 MSICOMPONENT *comp;
4297 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
4299 if (!lstrcmpW(comp->Component, component))
4300 return comp;
4303 return NULL;
4306 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4308 MSIPACKAGE *package = (MSIPACKAGE *)param;
4309 MSICOMPONENT *comp;
4310 SC_HANDLE scm, service = NULL;
4311 LPCWSTR name, *vector = NULL;
4312 LPWSTR args;
4313 DWORD event, numargs;
4314 UINT r = ERROR_FUNCTION_FAILED;
4316 comp = msi_find_component(package, MSI_RecordGetString(rec, 6));
4317 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4318 return ERROR_SUCCESS;
4320 name = MSI_RecordGetString(rec, 2);
4321 event = MSI_RecordGetInteger(rec, 3);
4322 args = strdupW(MSI_RecordGetString(rec, 4));
4324 if (!(event & msidbServiceControlEventStart))
4325 return ERROR_SUCCESS;
4327 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4328 if (!scm)
4330 ERR("Failed to open the service control manager\n");
4331 goto done;
4334 service = OpenServiceW(scm, name, SERVICE_START);
4335 if (!service)
4337 ERR("Failed to open service %s\n", debugstr_w(name));
4338 goto done;
4341 vector = msi_service_args_to_vector(name, args, &numargs);
4343 if (!StartServiceW(service, numargs, vector))
4345 ERR("Failed to start service %s\n", debugstr_w(name));
4346 goto done;
4349 r = ERROR_SUCCESS;
4351 done:
4352 CloseServiceHandle(service);
4353 CloseServiceHandle(scm);
4355 msi_free(args);
4356 msi_free(vector);
4357 return r;
4360 static UINT ACTION_StartServices( MSIPACKAGE *package )
4362 UINT rc;
4363 MSIQUERY *view;
4365 static const WCHAR query[] = {
4366 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4367 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4369 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4370 if (rc != ERROR_SUCCESS)
4371 return ERROR_SUCCESS;
4373 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4374 msiobj_release(&view->hdr);
4376 return rc;
4379 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4381 MSIFILE *file;
4383 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4385 if (!lstrcmpW(file->File, filename))
4386 return file;
4389 return NULL;
4392 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4394 MSIPACKAGE *package = (MSIPACKAGE*)param;
4395 LPWSTR driver, driver_path, ptr;
4396 WCHAR outpath[MAX_PATH];
4397 MSIFILE *driver_file, *setup_file;
4398 LPCWSTR desc;
4399 DWORD len, usage;
4400 UINT r = ERROR_SUCCESS;
4402 static const WCHAR driver_fmt[] = {
4403 'D','r','i','v','e','r','=','%','s',0};
4404 static const WCHAR setup_fmt[] = {
4405 'S','e','t','u','p','=','%','s',0};
4406 static const WCHAR usage_fmt[] = {
4407 'F','i','l','e','U','s','a','g','e','=','1',0};
4409 desc = MSI_RecordGetString(rec, 3);
4411 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4412 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4414 if (!driver_file || !setup_file)
4416 ERR("ODBC Driver entry not found!\n");
4417 return ERROR_FUNCTION_FAILED;
4420 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4421 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4422 lstrlenW(usage_fmt) + 1;
4423 driver = msi_alloc(len * sizeof(WCHAR));
4424 if (!driver)
4425 return ERROR_OUTOFMEMORY;
4427 ptr = driver;
4428 lstrcpyW(ptr, desc);
4429 ptr += lstrlenW(ptr) + 1;
4431 sprintfW(ptr, driver_fmt, driver_file->FileName);
4432 ptr += lstrlenW(ptr) + 1;
4434 sprintfW(ptr, setup_fmt, setup_file->FileName);
4435 ptr += lstrlenW(ptr) + 1;
4437 lstrcpyW(ptr, usage_fmt);
4438 ptr += lstrlenW(ptr) + 1;
4439 *ptr = '\0';
4441 driver_path = strdupW(driver_file->TargetPath);
4442 ptr = strrchrW(driver_path, '\\');
4443 if (ptr) *ptr = '\0';
4445 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4446 NULL, ODBC_INSTALL_COMPLETE, &usage))
4448 ERR("Failed to install SQL driver!\n");
4449 r = ERROR_FUNCTION_FAILED;
4452 msi_free(driver);
4453 msi_free(driver_path);
4455 return r;
4458 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4460 MSIPACKAGE *package = (MSIPACKAGE*)param;
4461 LPWSTR translator, translator_path, ptr;
4462 WCHAR outpath[MAX_PATH];
4463 MSIFILE *translator_file, *setup_file;
4464 LPCWSTR desc;
4465 DWORD len, usage;
4466 UINT r = ERROR_SUCCESS;
4468 static const WCHAR translator_fmt[] = {
4469 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4470 static const WCHAR setup_fmt[] = {
4471 'S','e','t','u','p','=','%','s',0};
4473 desc = MSI_RecordGetString(rec, 3);
4475 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4476 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4478 if (!translator_file || !setup_file)
4480 ERR("ODBC Translator entry not found!\n");
4481 return ERROR_FUNCTION_FAILED;
4484 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4485 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4486 translator = msi_alloc(len * sizeof(WCHAR));
4487 if (!translator)
4488 return ERROR_OUTOFMEMORY;
4490 ptr = translator;
4491 lstrcpyW(ptr, desc);
4492 ptr += lstrlenW(ptr) + 1;
4494 sprintfW(ptr, translator_fmt, translator_file->FileName);
4495 ptr += lstrlenW(ptr) + 1;
4497 sprintfW(ptr, setup_fmt, setup_file->FileName);
4498 ptr += lstrlenW(ptr) + 1;
4499 *ptr = '\0';
4501 translator_path = strdupW(translator_file->TargetPath);
4502 ptr = strrchrW(translator_path, '\\');
4503 if (ptr) *ptr = '\0';
4505 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4506 NULL, ODBC_INSTALL_COMPLETE, &usage))
4508 ERR("Failed to install SQL translator!\n");
4509 r = ERROR_FUNCTION_FAILED;
4512 msi_free(translator);
4513 msi_free(translator_path);
4515 return r;
4518 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4520 LPWSTR attrs;
4521 LPCWSTR desc, driver;
4522 WORD request = ODBC_ADD_SYS_DSN;
4523 INT registration;
4524 DWORD len;
4525 UINT r = ERROR_SUCCESS;
4527 static const WCHAR attrs_fmt[] = {
4528 'D','S','N','=','%','s',0 };
4530 desc = MSI_RecordGetString(rec, 3);
4531 driver = MSI_RecordGetString(rec, 4);
4532 registration = MSI_RecordGetInteger(rec, 5);
4534 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4535 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4537 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4538 attrs = msi_alloc(len * sizeof(WCHAR));
4539 if (!attrs)
4540 return ERROR_OUTOFMEMORY;
4542 sprintfW(attrs, attrs_fmt, desc);
4543 attrs[len - 1] = '\0';
4545 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4547 ERR("Failed to install SQL data source!\n");
4548 r = ERROR_FUNCTION_FAILED;
4551 msi_free(attrs);
4553 return r;
4556 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4558 UINT rc;
4559 MSIQUERY *view;
4561 static const WCHAR driver_query[] = {
4562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4563 'O','D','B','C','D','r','i','v','e','r',0 };
4565 static const WCHAR translator_query[] = {
4566 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4567 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4569 static const WCHAR source_query[] = {
4570 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4571 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4573 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4574 if (rc != ERROR_SUCCESS)
4575 return ERROR_SUCCESS;
4577 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4578 msiobj_release(&view->hdr);
4580 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4581 if (rc != ERROR_SUCCESS)
4582 return ERROR_SUCCESS;
4584 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4585 msiobj_release(&view->hdr);
4587 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4588 if (rc != ERROR_SUCCESS)
4589 return ERROR_SUCCESS;
4591 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4592 msiobj_release(&view->hdr);
4594 return rc;
4597 #define ENV_ACT_SETALWAYS 0x1
4598 #define ENV_ACT_SETABSENT 0x2
4599 #define ENV_ACT_REMOVE 0x4
4600 #define ENV_ACT_REMOVEMATCH 0x8
4602 #define ENV_MOD_MACHINE 0x20000000
4603 #define ENV_MOD_APPEND 0x40000000
4604 #define ENV_MOD_PREFIX 0x80000000
4605 #define ENV_MOD_MASK 0xC0000000
4607 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4609 static LONG env_set_flags( LPCWSTR *name, LPWSTR *value, DWORD *flags )
4611 LPCWSTR cptr = *name;
4612 LPWSTR ptr = *value;
4614 static const WCHAR prefix[] = {'[','~',']',0};
4616 *flags = 0;
4617 while (*cptr)
4619 if (*cptr == '=')
4620 *flags |= ENV_ACT_SETALWAYS;
4621 else if (*cptr == '+')
4622 *flags |= ENV_ACT_SETABSENT;
4623 else if (*cptr == '-')
4624 *flags |= ENV_ACT_REMOVE;
4625 else if (*cptr == '!')
4626 *flags |= ENV_ACT_REMOVEMATCH;
4627 else if (*cptr == '*')
4628 *flags |= ENV_MOD_MACHINE;
4629 else
4630 break;
4632 cptr++;
4633 (*name)++;
4636 if (!*cptr)
4638 ERR("Missing environment variable\n");
4639 return ERROR_FUNCTION_FAILED;
4642 if (!strncmpW(ptr, prefix, lstrlenW(prefix)))
4644 *flags |= ENV_MOD_PREFIX;
4645 *value += lstrlenW(prefix);
4647 else
4649 ptr += lstrlenW(ptr) - lstrlenW(prefix) - 1;
4650 if (!lstrcmpW(ptr, prefix))
4652 *flags |= ENV_MOD_APPEND;
4653 *ptr = '\0';
4657 if (!*flags ||
4658 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4659 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4660 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4661 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4663 ERR("Invalid flags: %08x\n", *flags);
4664 return ERROR_FUNCTION_FAILED;
4667 return ERROR_SUCCESS;
4670 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4672 MSIPACKAGE *package = param;
4673 LPCWSTR name, value, comp;
4674 LPWSTR data = NULL, newval = NULL;
4675 LPWSTR deformatted, ptr;
4676 DWORD flags, type, size;
4677 LONG res;
4678 HKEY env = NULL, root = HKEY_CURRENT_USER;
4680 static const WCHAR environment[] =
4681 {'S','y','s','t','e','m','\\',
4682 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4683 'C','o','n','t','r','o','l','\\',
4684 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4685 'E','n','v','i','r','o','n','m','e','n','t',0};
4686 static const WCHAR semicolon[] = {';',0};
4688 name = MSI_RecordGetString(rec, 2);
4689 value = MSI_RecordGetString(rec, 3);
4690 comp = MSI_RecordGetString(rec, 4);
4692 deformat_string(package, value, &deformatted);
4693 if (!deformatted)
4694 return ERROR_OUTOFMEMORY;
4696 res = env_set_flags(&name, &deformatted, &flags);
4697 if (res != ERROR_SUCCESS)
4698 goto done;
4700 value = deformatted;
4702 if (flags & ENV_MOD_MACHINE)
4703 root = HKEY_LOCAL_MACHINE;
4705 res = RegOpenKeyExW(root, environment, 0, KEY_ALL_ACCESS, &env);
4706 if (res != ERROR_SUCCESS)
4707 goto done;
4709 if (flags & ENV_ACT_REMOVE)
4710 FIXME("Not removing environment variable on uninstall!\n");
4712 size = 0;
4713 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
4714 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
4715 (res == ERROR_SUCCESS && type != REG_SZ))
4716 goto done;
4718 if (res != ERROR_FILE_NOT_FOUND)
4720 if (flags & ENV_ACT_SETABSENT)
4722 res = ERROR_SUCCESS;
4723 goto done;
4726 data = msi_alloc(size);
4727 if (!data)
4729 RegCloseKey(env);
4730 return ERROR_OUTOFMEMORY;
4733 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
4734 if (res != ERROR_SUCCESS)
4735 goto done;
4737 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
4739 res = RegDeleteKeyW(env, name);
4740 goto done;
4743 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
4744 newval = msi_alloc(size);
4745 ptr = newval;
4746 if (!newval)
4748 res = ERROR_OUTOFMEMORY;
4749 goto done;
4752 if (!(flags & ENV_MOD_MASK))
4753 lstrcpyW(newval, value);
4754 else
4756 if (flags & ENV_MOD_PREFIX)
4758 lstrcpyW(newval, value);
4759 lstrcatW(newval, semicolon);
4760 ptr = newval + lstrlenW(value) + 1;
4763 lstrcpyW(ptr, data);
4765 if (flags & ENV_MOD_APPEND)
4767 lstrcatW(newval, semicolon);
4768 lstrcatW(newval, value);
4772 else
4774 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
4775 newval = msi_alloc(size);
4776 if (!newval)
4778 res = ERROR_OUTOFMEMORY;
4779 goto done;
4782 lstrcpyW(newval, value);
4785 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
4786 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
4788 done:
4789 if (env) RegCloseKey(env);
4790 msi_free(deformatted);
4791 msi_free(data);
4792 msi_free(newval);
4793 return res;
4796 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4798 UINT rc;
4799 MSIQUERY * view;
4800 static const WCHAR ExecSeqQuery[] =
4801 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4802 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
4803 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4804 if (rc != ERROR_SUCCESS)
4805 return ERROR_SUCCESS;
4807 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
4808 msiobj_release(&view->hdr);
4810 return rc;
4813 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4814 LPCSTR action, LPCWSTR table )
4816 static const WCHAR query[] = {
4817 'S','E','L','E','C','T',' ','*',' ',
4818 'F','R','O','M',' ','`','%','s','`',0 };
4819 MSIQUERY *view = NULL;
4820 DWORD count = 0;
4821 UINT r;
4823 r = MSI_OpenQuery( package->db, &view, query, table );
4824 if (r == ERROR_SUCCESS)
4826 r = MSI_IterateRecords(view, &count, NULL, package);
4827 msiobj_release(&view->hdr);
4830 if (count)
4831 FIXME("%s -> %u ignored %s table values\n",
4832 action, count, debugstr_w(table));
4834 return ERROR_SUCCESS;
4837 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4839 TRACE("%p\n", package);
4840 return ERROR_SUCCESS;
4843 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4845 static const WCHAR table[] =
4846 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4847 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4850 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4852 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4853 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4856 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4858 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4859 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4862 static UINT ACTION_BindImage( MSIPACKAGE *package )
4864 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4865 return msi_unimplemented_action_stub( package, "BindImage", table );
4868 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4870 static const WCHAR table[] = {
4871 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4872 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4875 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4877 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4878 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4881 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4883 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4884 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4887 static UINT ACTION_StopServices( MSIPACKAGE *package )
4889 static const WCHAR table[] = {
4890 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4891 return msi_unimplemented_action_stub( package, "StopServices", table );
4894 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4896 static const WCHAR table[] = {
4897 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4898 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4900 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
4902 static const WCHAR table[] = {
4903 'P','r','o','d','u','c','t','I','D',0 };
4904 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
4907 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4909 static const WCHAR table[] = {
4910 'E','n','v','i','r','o','n','m','e','n','t',0 };
4911 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4914 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4916 static const WCHAR table[] = {
4917 'M','s','i','A','s','s','e','m','b','l','y',0 };
4918 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4921 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4923 static const WCHAR table[] = {
4924 'M','s','i','A','s','s','e','m','b','l','y',0 };
4925 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4928 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4930 static const WCHAR table[] = { 'F','o','n','t',0 };
4931 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4934 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4936 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4937 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4940 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4942 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4943 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4946 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4948 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4949 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4952 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4954 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4955 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4958 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
4960 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
4961 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
4964 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
4966 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
4967 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
4970 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
4972 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4973 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
4976 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
4978 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
4979 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
4982 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
4984 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
4985 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
4988 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
4990 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
4991 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
4994 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
4996 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
4997 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5000 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5002 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5003 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5006 static UINT ACTION_UnpublishFeatures( MSIPACKAGE *package )
5008 static const WCHAR table[] = { 'F','e','a','t','u','r','e','C','o','m','p','o','n','e','n','t','s',0 };
5009 return msi_unimplemented_action_stub( package, "UnpublishFeatures", table );
5012 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5014 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5015 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5018 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5020 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5021 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5024 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5026 static const WCHAR table[] = { 'M','I','M','E',0 };
5027 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5030 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5032 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5033 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5036 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5038 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5039 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5042 static const struct _actions StandardActions[] = {
5043 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5044 { szAppSearch, ACTION_AppSearch },
5045 { szBindImage, ACTION_BindImage },
5046 { szCCPSearch, ACTION_CCPSearch },
5047 { szCostFinalize, ACTION_CostFinalize },
5048 { szCostInitialize, ACTION_CostInitialize },
5049 { szCreateFolders, ACTION_CreateFolders },
5050 { szCreateShortcuts, ACTION_CreateShortcuts },
5051 { szDeleteServices, ACTION_DeleteServices },
5052 { szDisableRollback, NULL },
5053 { szDuplicateFiles, ACTION_DuplicateFiles },
5054 { szExecuteAction, ACTION_ExecuteAction },
5055 { szFileCost, ACTION_FileCost },
5056 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5057 { szForceReboot, ACTION_ForceReboot },
5058 { szInstallAdminPackage, NULL },
5059 { szInstallExecute, ACTION_InstallExecute },
5060 { szInstallExecuteAgain, ACTION_InstallExecute },
5061 { szInstallFiles, ACTION_InstallFiles},
5062 { szInstallFinalize, ACTION_InstallFinalize },
5063 { szInstallInitialize, ACTION_InstallInitialize },
5064 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5065 { szInstallValidate, ACTION_InstallValidate },
5066 { szIsolateComponents, ACTION_IsolateComponents },
5067 { szLaunchConditions, ACTION_LaunchConditions },
5068 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5069 { szMoveFiles, ACTION_MoveFiles },
5070 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5071 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5072 { szInstallODBC, ACTION_InstallODBC },
5073 { szInstallServices, ACTION_InstallServices },
5074 { szPatchFiles, ACTION_PatchFiles },
5075 { szProcessComponents, ACTION_ProcessComponents },
5076 { szPublishComponents, ACTION_PublishComponents },
5077 { szPublishFeatures, ACTION_PublishFeatures },
5078 { szPublishProduct, ACTION_PublishProduct },
5079 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5080 { szRegisterComPlus, ACTION_RegisterComPlus},
5081 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5082 { szRegisterFonts, ACTION_RegisterFonts },
5083 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5084 { szRegisterProduct, ACTION_RegisterProduct },
5085 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5086 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5087 { szRegisterUser, ACTION_RegisterUser },
5088 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5089 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5090 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5091 { szRemoveFiles, ACTION_RemoveFiles },
5092 { szRemoveFolders, ACTION_RemoveFolders },
5093 { szRemoveIniValues, ACTION_RemoveIniValues },
5094 { szRemoveODBC, ACTION_RemoveODBC },
5095 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5096 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5097 { szResolveSource, ACTION_ResolveSource },
5098 { szRMCCPSearch, ACTION_RMCCPSearch },
5099 { szScheduleReboot, NULL },
5100 { szSelfRegModules, ACTION_SelfRegModules },
5101 { szSelfUnregModules, ACTION_SelfUnregModules },
5102 { szSetODBCFolders, NULL },
5103 { szStartServices, ACTION_StartServices },
5104 { szStopServices, ACTION_StopServices },
5105 { szUnpublishComponents, ACTION_UnpublishComponents },
5106 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5107 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5108 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5109 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5110 { szUnregisterFonts, ACTION_UnregisterFonts },
5111 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5112 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5113 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5114 { szValidateProductID, ACTION_ValidateProductID },
5115 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5116 { szWriteIniValues, ACTION_WriteIniValues },
5117 { szWriteRegistryValues, ACTION_WriteRegistryValues },
5118 { NULL, NULL },