wined3d: Fix the texm3x3tex instruction to sample properly.
[wine/dibdrv.git] / dlls / msi / action.c
blob668b49e6a6b0eea4915cd31295e4023319f99a89
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 "wine/debug.h"
39 #include "msidefs.h"
40 #include "msipriv.h"
41 #include "winuser.h"
42 #include "shlobj.h"
43 #include "wine/unicode.h"
44 #include "winver.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 * Prototypes
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] =
117 {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] =
119 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120 'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] =
122 {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] =
124 {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] =
126 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] =
128 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] =
130 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] =
132 {'F','i','n','d','R','e','l','a','t','e','d',
133 'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] =
135 {'I','n','s','t','a','l','l','A','d','m','i','n',
136 'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] =
138 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139 'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] =
141 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] =
143 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144 'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] =
146 {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] =
148 {'M','s','i','P','u','b','l','i','s','h',
149 'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] =
151 {'M','s','i','U','n','p','u','b','l','i','s','h',
152 'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] =
154 {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] =
156 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] =
158 {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] =
160 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165 'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174 'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177 'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180 'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182 {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188 {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191 'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195 {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207 {'U','n','p','u','b','l','i','s','h',
208 'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213 'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217 {'U','n','r','e','g','i','s','t','e','r',
218 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225 'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228 'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233 'S','t','r','i','n','g','s',0};
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238 struct _actions {
239 LPCWSTR action;
240 STANDARDACTIONHANDLER handler;
243 static struct _actions StandardActions[];
246 /********************************************************
247 * helper functions
248 ********************************************************/
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
252 static const WCHAR Query_t[] =
253 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
256 ' ','\'','%','s','\'',0};
257 MSIRECORD * row;
259 row = MSI_QueryGetRecord( package->db, Query_t, action );
260 if (!row)
261 return;
262 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263 msiobj_release(&row->hdr);
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
267 UINT rc)
269 MSIRECORD * row;
270 static const WCHAR template_s[]=
271 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272 '%','s', '.',0};
273 static const WCHAR template_e[]=
274 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276 '%','i','.',0};
277 static const WCHAR format[] =
278 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
279 WCHAR message[1024];
280 WCHAR timet[0x100];
282 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283 if (start)
284 sprintfW(message,template_s,timet,action);
285 else
286 sprintfW(message,template_e,timet,action,rc);
288 row = MSI_CreateRecord(1);
289 MSI_RecordSetStringW(row,1,message);
291 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292 msiobj_release(&row->hdr);
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
297 LPCWSTR ptr,ptr2;
298 BOOL quote;
299 DWORD len;
300 LPWSTR prop = NULL, val = NULL;
302 if (!szCommandLine)
303 return ERROR_SUCCESS;
305 ptr = szCommandLine;
307 while (*ptr)
309 if (*ptr==' ')
311 ptr++;
312 continue;
315 TRACE("Looking at %s\n",debugstr_w(ptr));
317 ptr2 = strchrW(ptr,'=');
318 if (!ptr2)
320 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
321 break;
324 quote = FALSE;
326 len = ptr2-ptr;
327 prop = msi_alloc((len+1)*sizeof(WCHAR));
328 memcpy(prop,ptr,len*sizeof(WCHAR));
329 prop[len]=0;
330 ptr2++;
332 len = 0;
333 ptr = ptr2;
334 while (*ptr && (quote || (!quote && *ptr!=' ')))
336 if (*ptr == '"')
337 quote = !quote;
338 ptr++;
339 len++;
342 if (*ptr2=='"')
344 ptr2++;
345 len -= 2;
347 val = msi_alloc((len+1)*sizeof(WCHAR));
348 memcpy(val,ptr2,len*sizeof(WCHAR));
349 val[len] = 0;
351 if (lstrlenW(prop) > 0)
353 TRACE("Found commandline property (%s) = (%s)\n",
354 debugstr_w(prop), debugstr_w(val));
355 MSI_SetPropertyW(package,prop,val);
357 msi_free(val);
358 msi_free(prop);
361 return ERROR_SUCCESS;
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367 LPCWSTR pc;
368 LPWSTR p, *ret = NULL;
369 UINT count = 0;
371 if (!str)
372 return ret;
374 /* count the number of substrings */
375 for ( pc = str, count = 0; pc; count++ )
377 pc = strchrW( pc, sep );
378 if (pc)
379 pc++;
382 /* allocate space for an array of substring pointers and the substrings */
383 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384 (lstrlenW(str)+1) * sizeof(WCHAR) );
385 if (!ret)
386 return ret;
388 /* copy the string and set the pointers */
389 p = (LPWSTR) &ret[count+1];
390 lstrcpyW( p, str );
391 for( count = 0; (ret[count] = p); count++ )
393 p = strchrW( p, sep );
394 if (p)
395 *p++ = 0;
398 return ret;
401 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
403 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
404 LPWSTR prod_code, patch_product;
405 UINT ret;
407 prod_code = msi_dup_property( package, szProductCode );
408 patch_product = msi_get_suminfo_product( patch );
410 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
412 if ( strstrW( patch_product, prod_code ) )
413 ret = ERROR_SUCCESS;
414 else
415 ret = ERROR_FUNCTION_FAILED;
417 msi_free( patch_product );
418 msi_free( prod_code );
420 return ret;
423 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
424 MSIDATABASE *patch_db, LPCWSTR name )
426 UINT ret = ERROR_FUNCTION_FAILED;
427 IStorage *stg = NULL;
428 HRESULT r;
430 TRACE("%p %s\n", package, debugstr_w(name) );
432 if (*name++ != ':')
434 ERR("expected a colon in %s\n", debugstr_w(name));
435 return ERROR_FUNCTION_FAILED;
438 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
439 if (SUCCEEDED(r))
441 ret = msi_check_transform_applicable( package, stg );
442 if (ret == ERROR_SUCCESS)
443 msi_table_apply_transform( package->db, stg );
444 else
445 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
446 IStorage_Release( stg );
448 else
449 ERR("failed to open substorage %s\n", debugstr_w(name));
451 return ERROR_SUCCESS;
454 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
456 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
457 LPWSTR guid_list, *guids, product_id;
458 UINT i, ret = ERROR_FUNCTION_FAILED;
460 product_id = msi_dup_property( package, szProdID );
461 if (!product_id)
463 /* FIXME: the property ProductID should be written into the DB somewhere */
464 ERR("no product ID to check\n");
465 return ERROR_SUCCESS;
468 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
469 guids = msi_split_string( guid_list, ';' );
470 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
472 if (!lstrcmpW( guids[i], product_id ))
473 ret = ERROR_SUCCESS;
475 msi_free( guids );
476 msi_free( guid_list );
477 msi_free( product_id );
479 return ret;
482 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
484 MSISUMMARYINFO *si;
485 LPWSTR str, *substorage;
486 UINT i, r = ERROR_SUCCESS;
488 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
489 if (!si)
490 return ERROR_FUNCTION_FAILED;
492 msi_check_patch_applicable( package, si );
494 /* enumerate the substorage */
495 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
496 substorage = msi_split_string( str, ';' );
497 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
498 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
499 msi_free( substorage );
500 msi_free( str );
502 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
504 msiobj_release( &si->hdr );
506 return r;
509 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
511 MSIDATABASE *patch_db = NULL;
512 UINT r;
514 TRACE("%p %s\n", package, debugstr_w( file ) );
516 /* FIXME:
517 * We probably want to make sure we only open a patch collection here.
518 * Patch collections (.msp) and databases (.msi) have different GUIDs
519 * but currently MSI_OpenDatabaseW will accept both.
521 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
522 if ( r != ERROR_SUCCESS )
524 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
525 return r;
528 msi_parse_patch_summary( package, patch_db );
531 * There might be a CAB file in the patch package,
532 * so append it to the list of storage to search for streams.
534 append_storage_to_db( package->db, patch_db->storage );
536 msiobj_release( &patch_db->hdr );
538 return ERROR_SUCCESS;
541 /* get the PATCH property, and apply all the patches it specifies */
542 static UINT msi_apply_patches( MSIPACKAGE *package )
544 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
545 LPWSTR patch_list, *patches;
546 UINT i, r = ERROR_SUCCESS;
548 patch_list = msi_dup_property( package, szPatch );
550 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
552 patches = msi_split_string( patch_list, ';' );
553 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
554 r = msi_apply_patch_package( package, patches[i] );
556 msi_free( patches );
557 msi_free( patch_list );
559 return r;
562 static UINT msi_apply_transforms( MSIPACKAGE *package )
564 static const WCHAR szTransforms[] = {
565 'T','R','A','N','S','F','O','R','M','S',0 };
566 LPWSTR xform_list, *xforms;
567 UINT i, r = ERROR_SUCCESS;
569 xform_list = msi_dup_property( package, szTransforms );
570 xforms = msi_split_string( xform_list, ';' );
572 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
574 if (xforms[i][0] == ':')
575 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
576 else
577 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
580 msi_free( xforms );
581 msi_free( xform_list );
583 return r;
586 /****************************************************
587 * TOP level entry points
588 *****************************************************/
590 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
591 LPCWSTR szCommandLine )
593 UINT rc;
594 BOOL ui = FALSE;
595 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
596 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
597 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
599 MSI_SetPropertyW(package, szAction, szInstall);
601 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
603 package->script->InWhatSequence = SEQUENCE_INSTALL;
605 if (szPackagePath)
607 LPWSTR p, check, path;
609 path = strdupW(szPackagePath);
610 p = strrchrW(path,'\\');
611 if (p)
613 p++;
614 *p=0;
616 else
618 msi_free(path);
619 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
620 GetCurrentDirectoryW(MAX_PATH,path);
621 strcatW(path,cszbs);
624 check = msi_dup_property( package, cszSourceDir );
625 if (!check)
626 MSI_SetPropertyW(package, cszSourceDir, path);
627 msi_free(check);
629 check = msi_dup_property( package, cszSOURCEDIR );
630 if (!check)
631 MSI_SetPropertyW(package, cszSOURCEDIR, path);
633 msi_free( package->PackagePath );
634 package->PackagePath = path;
636 msi_free(check);
639 msi_parse_command_line( package, szCommandLine );
641 msi_apply_transforms( package );
642 msi_apply_patches( package );
644 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
646 package->script->InWhatSequence |= SEQUENCE_UI;
647 rc = ACTION_ProcessUISequence(package);
648 ui = TRUE;
649 if (rc == ERROR_SUCCESS)
651 package->script->InWhatSequence |= SEQUENCE_EXEC;
652 rc = ACTION_ProcessExecSequence(package,TRUE);
655 else
656 rc = ACTION_ProcessExecSequence(package,FALSE);
658 if (rc == -1)
660 /* install was halted but should be considered a success */
661 rc = ERROR_SUCCESS;
664 package->script->CurrentlyScripting= FALSE;
666 /* process the ending type action */
667 if (rc == ERROR_SUCCESS)
668 ACTION_PerformActionSequence(package,-1,ui);
669 else if (rc == ERROR_INSTALL_USEREXIT)
670 ACTION_PerformActionSequence(package,-2,ui);
671 else if (rc == ERROR_INSTALL_SUSPEND)
672 ACTION_PerformActionSequence(package,-4,ui);
673 else /* failed */
674 ACTION_PerformActionSequence(package,-3,ui);
676 /* finish up running custom actions */
677 ACTION_FinishCustomActions(package);
679 return rc;
682 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
684 UINT rc = ERROR_SUCCESS;
685 MSIRECORD * row = 0;
686 static const WCHAR ExecSeqQuery[] =
687 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
688 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
689 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
690 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
692 static const WCHAR UISeqQuery[] =
693 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
694 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
695 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
696 ' ', '=',' ','%','i',0};
698 if (UI)
699 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
700 else
701 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
703 if (row)
705 LPCWSTR action, cond;
707 TRACE("Running the actions\n");
709 /* check conditions */
710 cond = MSI_RecordGetString(row,2);
712 /* this is a hack to skip errors in the condition code */
713 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
714 goto end;
716 action = MSI_RecordGetString(row,1);
717 if (!action)
719 ERR("failed to fetch action\n");
720 rc = ERROR_FUNCTION_FAILED;
721 goto end;
724 if (UI)
725 rc = ACTION_PerformUIAction(package,action);
726 else
727 rc = ACTION_PerformAction(package,action,FALSE);
728 end:
729 msiobj_release(&row->hdr);
731 else
732 rc = ERROR_SUCCESS;
734 return rc;
737 typedef struct {
738 MSIPACKAGE* package;
739 BOOL UI;
740 } iterate_action_param;
742 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
744 iterate_action_param *iap= (iterate_action_param*)param;
745 UINT rc;
746 LPCWSTR cond, action;
748 action = MSI_RecordGetString(row,1);
749 if (!action)
751 ERR("Error is retrieving action name\n");
752 return ERROR_FUNCTION_FAILED;
755 /* check conditions */
756 cond = MSI_RecordGetString(row,2);
758 /* this is a hack to skip errors in the condition code */
759 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
761 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
762 return ERROR_SUCCESS;
765 if (iap->UI)
766 rc = ACTION_PerformUIAction(iap->package,action);
767 else
768 rc = ACTION_PerformAction(iap->package,action,FALSE);
770 msi_dialog_check_messages( NULL );
772 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
773 rc = iap->package->CurrentInstallState;
775 if (rc == ERROR_FUNCTION_NOT_CALLED)
776 rc = ERROR_SUCCESS;
778 if (rc != ERROR_SUCCESS)
779 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
781 return rc;
784 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
786 MSIQUERY * view;
787 UINT r;
788 static const WCHAR query[] =
789 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
790 '`','%','s','`',
791 ' ','W','H','E','R','E',' ',
792 '`','S','e','q','u','e','n','c','e','`',' ',
793 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
794 '`','S','e','q','u','e','n','c','e','`',0};
795 iterate_action_param iap;
798 * FIXME: probably should be checking UILevel in the
799 * ACTION_PerformUIAction/ACTION_PerformAction
800 * rather than saving the UI level here. Those
801 * two functions can be merged too.
803 iap.package = package;
804 iap.UI = TRUE;
806 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
808 r = MSI_OpenQuery( package->db, &view, query, szTable );
809 if (r == ERROR_SUCCESS)
811 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
812 msiobj_release(&view->hdr);
815 return r;
818 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
820 MSIQUERY * view;
821 UINT rc;
822 static const WCHAR ExecSeqQuery[] =
823 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
824 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
825 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
826 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
827 'O','R','D','E','R',' ', 'B','Y',' ',
828 '`','S','e','q','u','e','n','c','e','`',0 };
829 MSIRECORD * row = 0;
830 static const WCHAR IVQuery[] =
831 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
832 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
833 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
834 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
835 ' ','\'', 'I','n','s','t','a','l','l',
836 'V','a','l','i','d','a','t','e','\'', 0};
837 INT seq = 0;
838 iterate_action_param iap;
840 iap.package = package;
841 iap.UI = FALSE;
843 if (package->script->ExecuteSequenceRun)
845 TRACE("Execute Sequence already Run\n");
846 return ERROR_SUCCESS;
849 package->script->ExecuteSequenceRun = TRUE;
851 /* get the sequence number */
852 if (UIran)
854 row = MSI_QueryGetRecord(package->db, IVQuery);
855 if( !row )
856 return ERROR_FUNCTION_FAILED;
857 seq = MSI_RecordGetInteger(row,1);
858 msiobj_release(&row->hdr);
861 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
862 if (rc == ERROR_SUCCESS)
864 TRACE("Running the actions\n");
866 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
867 msiobj_release(&view->hdr);
870 return rc;
873 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
875 MSIQUERY * view;
876 UINT rc;
877 static const WCHAR ExecSeqQuery [] =
878 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
879 '`','I','n','s','t','a','l','l',
880 'U','I','S','e','q','u','e','n','c','e','`',
881 ' ','W','H','E','R','E',' ',
882 '`','S','e','q','u','e','n','c','e','`',' ',
883 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
884 '`','S','e','q','u','e','n','c','e','`',0};
885 iterate_action_param iap;
887 iap.package = package;
888 iap.UI = TRUE;
890 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
892 if (rc == ERROR_SUCCESS)
894 TRACE("Running the actions\n");
896 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
897 msiobj_release(&view->hdr);
900 return rc;
903 /********************************************************
904 * ACTION helper functions and functions that perform the actions
905 *******************************************************/
906 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
907 UINT* rc, BOOL force )
909 BOOL ret = FALSE;
910 BOOL run = force;
911 int i;
913 if (!run && !package->script->CurrentlyScripting)
914 run = TRUE;
916 if (!run)
918 if (strcmpW(action,szInstallFinalize) == 0 ||
919 strcmpW(action,szInstallExecute) == 0 ||
920 strcmpW(action,szInstallExecuteAgain) == 0)
921 run = TRUE;
924 i = 0;
925 while (StandardActions[i].action != NULL)
927 if (strcmpW(StandardActions[i].action, action)==0)
929 if (!run)
931 ui_actioninfo(package, action, TRUE, 0);
932 *rc = schedule_action(package,INSTALL_SCRIPT,action);
933 ui_actioninfo(package, action, FALSE, *rc);
935 else
937 ui_actionstart(package, action);
938 if (StandardActions[i].handler)
940 *rc = StandardActions[i].handler(package);
942 else
944 FIXME("unhandled standard action %s\n",debugstr_w(action));
945 *rc = ERROR_SUCCESS;
948 ret = TRUE;
949 break;
951 i++;
953 return ret;
956 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
957 UINT* rc, BOOL force )
959 BOOL ret=FALSE;
960 UINT arc;
962 arc = ACTION_CustomAction(package,action, force);
964 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
966 *rc = arc;
967 ret = TRUE;
969 return ret;
973 * A lot of actions are really important even if they don't do anything
974 * explicit... Lots of properties are set at the beginning of the installation
975 * CostFinalize does a bunch of work to translate the directories and such
977 * But until I get write access to the database that is hard, so I am going to
978 * hack it to see if I can get something to run.
980 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
982 UINT rc = ERROR_SUCCESS;
983 BOOL handled;
985 TRACE("Performing action (%s)\n",debugstr_w(action));
987 handled = ACTION_HandleStandardAction(package, action, &rc, force);
989 if (!handled)
990 handled = ACTION_HandleCustomAction(package, action, &rc, force);
992 if (!handled)
994 FIXME("unhandled msi action %s\n",debugstr_w(action));
995 rc = ERROR_FUNCTION_NOT_CALLED;
998 return rc;
1001 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1003 UINT rc = ERROR_SUCCESS;
1004 BOOL handled = FALSE;
1006 TRACE("Performing action (%s)\n",debugstr_w(action));
1008 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1010 if (!handled)
1011 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1013 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1014 handled = TRUE;
1016 if (!handled)
1018 FIXME("unhandled msi action %s\n",debugstr_w(action));
1019 rc = ERROR_FUNCTION_NOT_CALLED;
1022 return rc;
1027 * Actual Action Handlers
1030 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1032 MSIPACKAGE *package = (MSIPACKAGE*)param;
1033 LPCWSTR dir;
1034 LPWSTR full_path;
1035 MSIRECORD *uirow;
1036 MSIFOLDER *folder;
1038 dir = MSI_RecordGetString(row,1);
1039 if (!dir)
1041 ERR("Unable to get folder id\n");
1042 return ERROR_SUCCESS;
1045 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1046 if (!full_path)
1048 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1049 return ERROR_SUCCESS;
1052 TRACE("Folder is %s\n",debugstr_w(full_path));
1054 /* UI stuff */
1055 uirow = MSI_CreateRecord(1);
1056 MSI_RecordSetStringW(uirow,1,full_path);
1057 ui_actiondata(package,szCreateFolders,uirow);
1058 msiobj_release( &uirow->hdr );
1060 if (folder->State == 0)
1061 create_full_pathW(full_path);
1063 folder->State = 3;
1065 msi_free(full_path);
1066 return ERROR_SUCCESS;
1069 /* FIXME: probably should merge this with the above function */
1070 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1072 UINT rc = ERROR_SUCCESS;
1073 MSIFOLDER *folder;
1074 LPWSTR install_path;
1076 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1077 if (!install_path)
1078 return ERROR_FUNCTION_FAILED;
1080 /* create the path */
1081 if (folder->State == 0)
1083 create_full_pathW(install_path);
1084 folder->State = 2;
1086 msi_free(install_path);
1088 return rc;
1091 UINT msi_create_component_directories( MSIPACKAGE *package )
1093 MSICOMPONENT *comp;
1095 /* create all the folders required by the components are going to install */
1096 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1098 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1099 continue;
1100 msi_create_directory( package, comp->Directory );
1103 return ERROR_SUCCESS;
1107 * Also we cannot enable/disable components either, so for now I am just going
1108 * to do all the directories for all the components.
1110 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1112 static const WCHAR ExecSeqQuery[] =
1113 {'S','E','L','E','C','T',' ',
1114 '`','D','i','r','e','c','t','o','r','y','_','`',
1115 ' ','F','R','O','M',' ',
1116 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1117 UINT rc;
1118 MSIQUERY *view;
1120 /* create all the empty folders specified in the CreateFolder table */
1121 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1122 if (rc != ERROR_SUCCESS)
1123 return ERROR_SUCCESS;
1125 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1126 msiobj_release(&view->hdr);
1128 msi_create_component_directories( package );
1130 return rc;
1133 static UINT load_component( MSIRECORD *row, LPVOID param )
1135 MSIPACKAGE *package = param;
1136 MSICOMPONENT *comp;
1138 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1139 if (!comp)
1140 return ERROR_FUNCTION_FAILED;
1142 list_add_tail( &package->components, &comp->entry );
1144 /* fill in the data */
1145 comp->Component = msi_dup_record_field( row, 1 );
1147 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1149 comp->ComponentId = msi_dup_record_field( row, 2 );
1150 comp->Directory = msi_dup_record_field( row, 3 );
1151 comp->Attributes = MSI_RecordGetInteger(row,4);
1152 comp->Condition = msi_dup_record_field( row, 5 );
1153 comp->KeyPath = msi_dup_record_field( row, 6 );
1155 comp->Installed = INSTALLSTATE_UNKNOWN;
1156 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1158 return ERROR_SUCCESS;
1161 static UINT load_all_components( MSIPACKAGE *package )
1163 static const WCHAR query[] = {
1164 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1165 '`','C','o','m','p','o','n','e','n','t','`',0 };
1166 MSIQUERY *view;
1167 UINT r;
1169 if (!list_empty(&package->components))
1170 return ERROR_SUCCESS;
1172 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1173 if (r != ERROR_SUCCESS)
1174 return r;
1176 r = MSI_IterateRecords(view, NULL, load_component, package);
1177 msiobj_release(&view->hdr);
1178 return r;
1181 typedef struct {
1182 MSIPACKAGE *package;
1183 MSIFEATURE *feature;
1184 } _ilfs;
1186 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1188 ComponentList *cl;
1190 cl = msi_alloc( sizeof (*cl) );
1191 if ( !cl )
1192 return ERROR_NOT_ENOUGH_MEMORY;
1193 cl->component = comp;
1194 list_add_tail( &feature->Components, &cl->entry );
1196 return ERROR_SUCCESS;
1199 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1201 FeatureList *fl;
1203 fl = msi_alloc( sizeof(*fl) );
1204 if ( !fl )
1205 return ERROR_NOT_ENOUGH_MEMORY;
1206 fl->feature = child;
1207 list_add_tail( &parent->Children, &fl->entry );
1209 return ERROR_SUCCESS;
1212 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1214 _ilfs* ilfs= (_ilfs*)param;
1215 LPCWSTR component;
1216 MSICOMPONENT *comp;
1218 component = MSI_RecordGetString(row,1);
1220 /* check to see if the component is already loaded */
1221 comp = get_loaded_component( ilfs->package, component );
1222 if (!comp)
1224 ERR("unknown component %s\n", debugstr_w(component));
1225 return ERROR_FUNCTION_FAILED;
1228 add_feature_component( ilfs->feature, comp );
1229 comp->Enabled = TRUE;
1231 return ERROR_SUCCESS;
1234 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1236 MSIFEATURE *feature;
1238 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1240 if ( !lstrcmpW( feature->Feature, name ) )
1241 return feature;
1244 return NULL;
1247 static UINT load_feature(MSIRECORD * row, LPVOID param)
1249 MSIPACKAGE* package = (MSIPACKAGE*)param;
1250 MSIFEATURE* feature;
1251 static const WCHAR Query1[] =
1252 {'S','E','L','E','C','T',' ',
1253 '`','C','o','m','p','o','n','e','n','t','_','`',
1254 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1255 'C','o','m','p','o','n','e','n','t','s','`',' ',
1256 'W','H','E','R','E',' ',
1257 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1258 MSIQUERY * view;
1259 UINT rc;
1260 _ilfs ilfs;
1262 /* fill in the data */
1264 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1265 if (!feature)
1266 return ERROR_NOT_ENOUGH_MEMORY;
1268 list_init( &feature->Children );
1269 list_init( &feature->Components );
1271 feature->Feature = msi_dup_record_field( row, 1 );
1273 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1275 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1276 feature->Title = msi_dup_record_field( row, 3 );
1277 feature->Description = msi_dup_record_field( row, 4 );
1279 if (!MSI_RecordIsNull(row,5))
1280 feature->Display = MSI_RecordGetInteger(row,5);
1282 feature->Level= MSI_RecordGetInteger(row,6);
1283 feature->Directory = msi_dup_record_field( row, 7 );
1284 feature->Attributes = MSI_RecordGetInteger(row,8);
1286 feature->Installed = INSTALLSTATE_UNKNOWN;
1287 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1289 list_add_tail( &package->features, &feature->entry );
1291 /* load feature components */
1293 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1294 if (rc != ERROR_SUCCESS)
1295 return ERROR_SUCCESS;
1297 ilfs.package = package;
1298 ilfs.feature = feature;
1300 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1301 msiobj_release(&view->hdr);
1303 return ERROR_SUCCESS;
1306 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1308 MSIPACKAGE* package = (MSIPACKAGE*)param;
1309 MSIFEATURE *parent, *child;
1311 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1312 if (!child)
1313 return ERROR_FUNCTION_FAILED;
1315 if (!child->Feature_Parent)
1316 return ERROR_SUCCESS;
1318 parent = find_feature_by_name( package, child->Feature_Parent );
1319 if (!parent)
1320 return ERROR_FUNCTION_FAILED;
1322 add_feature_child( parent, child );
1323 return ERROR_SUCCESS;
1326 static UINT load_all_features( MSIPACKAGE *package )
1328 static const WCHAR query[] = {
1329 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1330 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1331 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1332 MSIQUERY *view;
1333 UINT r;
1335 if (!list_empty(&package->features))
1336 return ERROR_SUCCESS;
1338 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1339 if (r != ERROR_SUCCESS)
1340 return r;
1342 r = MSI_IterateRecords( view, NULL, load_feature, package );
1343 if (r != ERROR_SUCCESS)
1344 return r;
1346 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1347 msiobj_release( &view->hdr );
1349 return r;
1352 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1354 if (!p)
1355 return p;
1356 p = strchrW(p, ch);
1357 if (!p)
1358 return p;
1359 *p = 0;
1360 return p+1;
1363 static UINT load_file(MSIRECORD *row, LPVOID param)
1365 MSIPACKAGE* package = (MSIPACKAGE*)param;
1366 LPCWSTR component;
1367 MSIFILE *file;
1369 /* fill in the data */
1371 file = msi_alloc_zero( sizeof (MSIFILE) );
1372 if (!file)
1373 return ERROR_NOT_ENOUGH_MEMORY;
1375 file->File = msi_dup_record_field( row, 1 );
1377 component = MSI_RecordGetString( row, 2 );
1378 file->Component = get_loaded_component( package, component );
1380 if (!file->Component)
1381 ERR("Unfound Component %s\n",debugstr_w(component));
1383 file->FileName = msi_dup_record_field( row, 3 );
1384 reduce_to_longfilename( file->FileName );
1386 file->ShortName = msi_dup_record_field( row, 3 );
1387 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1389 file->FileSize = MSI_RecordGetInteger( row, 4 );
1390 file->Version = msi_dup_record_field( row, 5 );
1391 file->Language = msi_dup_record_field( row, 6 );
1392 file->Attributes = MSI_RecordGetInteger( row, 7 );
1393 file->Sequence = MSI_RecordGetInteger( row, 8 );
1395 file->state = msifs_invalid;
1397 /* if the compressed bits are not set in the file attributes,
1398 * then read the information from the package word count property
1400 if (file->Attributes & msidbFileAttributesCompressed)
1402 file->IsCompressed = TRUE;
1404 else if (file->Attributes & msidbFileAttributesNoncompressed)
1406 file->IsCompressed = FALSE;
1408 else
1410 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1413 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1415 list_add_tail( &package->files, &file->entry );
1417 return ERROR_SUCCESS;
1420 static UINT load_all_files(MSIPACKAGE *package)
1422 MSIQUERY * view;
1423 UINT rc;
1424 static const WCHAR Query[] =
1425 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1426 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1427 '`','S','e','q','u','e','n','c','e','`', 0};
1429 if (!list_empty(&package->files))
1430 return ERROR_SUCCESS;
1432 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1433 if (rc != ERROR_SUCCESS)
1434 return ERROR_SUCCESS;
1436 rc = MSI_IterateRecords(view, NULL, load_file, package);
1437 msiobj_release(&view->hdr);
1439 return ERROR_SUCCESS;
1442 static UINT load_folder( MSIRECORD *row, LPVOID param )
1444 MSIPACKAGE *package = param;
1445 static const WCHAR szDot[] = { '.',0 };
1446 static WCHAR szEmpty[] = { 0 };
1447 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1448 MSIFOLDER *folder;
1450 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1451 if (!folder)
1452 return ERROR_NOT_ENOUGH_MEMORY;
1454 folder->Directory = msi_dup_record_field( row, 1 );
1456 TRACE("%s\n", debugstr_w(folder->Directory));
1458 p = msi_dup_record_field(row, 3);
1460 /* split src and target dir */
1461 tgt_short = p;
1462 src_short = folder_split_path( p, ':' );
1464 /* split the long and short paths */
1465 tgt_long = folder_split_path( tgt_short, '|' );
1466 src_long = folder_split_path( src_short, '|' );
1468 /* check for no-op dirs */
1469 if (!lstrcmpW(szDot, tgt_short))
1470 tgt_short = szEmpty;
1471 if (!lstrcmpW(szDot, src_short))
1472 src_short = szEmpty;
1474 if (!tgt_long)
1475 tgt_long = tgt_short;
1477 if (!src_short) {
1478 src_short = tgt_short;
1479 src_long = tgt_long;
1482 if (!src_long)
1483 src_long = src_short;
1485 /* FIXME: use the target short path too */
1486 folder->TargetDefault = strdupW(tgt_long);
1487 folder->SourceShortPath = strdupW(src_short);
1488 folder->SourceLongPath = strdupW(src_long);
1489 msi_free(p);
1491 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1492 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1493 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1495 folder->Parent = msi_dup_record_field( row, 2 );
1497 folder->Property = msi_dup_property( package, folder->Directory );
1499 list_add_tail( &package->folders, &folder->entry );
1501 TRACE("returning %p\n", folder);
1503 return ERROR_SUCCESS;
1506 static UINT load_all_folders( MSIPACKAGE *package )
1508 static const WCHAR query[] = {
1509 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1510 '`','D','i','r','e','c','t','o','r','y','`',0 };
1511 MSIQUERY *view;
1512 UINT r;
1514 if (!list_empty(&package->folders))
1515 return ERROR_SUCCESS;
1517 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1518 if (r != ERROR_SUCCESS)
1519 return r;
1521 r = MSI_IterateRecords(view, NULL, load_folder, package);
1522 msiobj_release(&view->hdr);
1523 return r;
1527 * I am not doing any of the costing functionality yet.
1528 * Mostly looking at doing the Component and Feature loading
1530 * The native MSI does A LOT of modification to tables here. Mostly adding
1531 * a lot of temporary columns to the Feature and Component tables.
1533 * note: Native msi also tracks the short filename. But I am only going to
1534 * track the long ones. Also looking at this directory table
1535 * it appears that the directory table does not get the parents
1536 * resolved base on property only based on their entries in the
1537 * directory table.
1539 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1541 static const WCHAR szCosting[] =
1542 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1543 static const WCHAR szZero[] = { '0', 0 };
1545 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1546 return ERROR_SUCCESS;
1548 MSI_SetPropertyW(package, szCosting, szZero);
1549 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1551 load_all_components( package );
1552 load_all_features( package );
1553 load_all_files( package );
1554 load_all_folders( package );
1556 return ERROR_SUCCESS;
1559 static UINT execute_script(MSIPACKAGE *package, UINT script )
1561 int i;
1562 UINT rc = ERROR_SUCCESS;
1564 TRACE("Executing Script %i\n",script);
1566 if (!package->script)
1568 ERR("no script!\n");
1569 return ERROR_FUNCTION_FAILED;
1572 for (i = 0; i < package->script->ActionCount[script]; i++)
1574 LPWSTR action;
1575 action = package->script->Actions[script][i];
1576 ui_actionstart(package, action);
1577 TRACE("Executing Action (%s)\n",debugstr_w(action));
1578 rc = ACTION_PerformAction(package, action, TRUE);
1579 if (rc != ERROR_SUCCESS)
1580 break;
1582 msi_free_action_script(package, script);
1583 return rc;
1586 static UINT ACTION_FileCost(MSIPACKAGE *package)
1588 return ERROR_SUCCESS;
1591 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1593 MSICOMPONENT *comp;
1595 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1597 INSTALLSTATE res;
1599 if (!comp->ComponentId)
1600 continue;
1602 res = MsiGetComponentPathW( package->ProductCode,
1603 comp->ComponentId, NULL, NULL);
1604 if (res < 0)
1605 res = INSTALLSTATE_ABSENT;
1606 comp->Installed = res;
1610 /* scan for and update current install states */
1611 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1613 MSICOMPONENT *comp;
1614 MSIFEATURE *feature;
1616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1618 ComponentList *cl;
1619 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1621 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1623 comp= cl->component;
1625 if (!comp->ComponentId)
1627 res = INSTALLSTATE_ABSENT;
1628 break;
1631 if (res == INSTALLSTATE_ABSENT)
1632 res = comp->Installed;
1633 else
1635 if (res == comp->Installed)
1636 continue;
1638 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1639 res != INSTALLSTATE_SOURCE)
1641 res = INSTALLSTATE_INCOMPLETE;
1645 feature->Installed = res;
1649 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1650 INSTALLSTATE state)
1652 static const WCHAR all[]={'A','L','L',0};
1653 LPWSTR override;
1654 MSIFEATURE *feature;
1656 override = msi_dup_property( package, property );
1657 if (!override)
1658 return FALSE;
1660 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1662 if (strcmpiW(override,all)==0)
1663 msi_feature_set_state( feature, state );
1664 else
1666 LPWSTR ptr = override;
1667 LPWSTR ptr2 = strchrW(override,',');
1669 while (ptr)
1671 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1672 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1674 msi_feature_set_state( feature, state );
1675 break;
1677 if (ptr2)
1679 ptr=ptr2+1;
1680 ptr2 = strchrW(ptr,',');
1682 else
1683 break;
1687 msi_free(override);
1689 return TRUE;
1692 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1694 int install_level;
1695 static const WCHAR szlevel[] =
1696 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1697 static const WCHAR szAddLocal[] =
1698 {'A','D','D','L','O','C','A','L',0};
1699 static const WCHAR szRemove[] =
1700 {'R','E','M','O','V','E',0};
1701 static const WCHAR szReinstall[] =
1702 {'R','E','I','N','S','T','A','L','L',0};
1703 BOOL override = FALSE;
1704 MSICOMPONENT* component;
1705 MSIFEATURE *feature;
1708 /* I do not know if this is where it should happen.. but */
1710 TRACE("Checking Install Level\n");
1712 install_level = msi_get_property_int( package, szlevel, 1 );
1714 /* ok here is the _real_ rub
1715 * all these activation/deactivation things happen in order and things
1716 * later on the list override things earlier on the list.
1717 * 1) INSTALLLEVEL processing
1718 * 2) ADDLOCAL
1719 * 3) REMOVE
1720 * 4) ADDSOURCE
1721 * 5) ADDDEFAULT
1722 * 6) REINSTALL
1723 * 7) COMPADDLOCAL
1724 * 8) COMPADDSOURCE
1725 * 9) FILEADDLOCAL
1726 * 10) FILEADDSOURCE
1727 * 11) FILEADDDEFAULT
1728 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1729 * ignored for all the features. seems strange, especially since it is not
1730 * documented anywhere, but it is how it works.
1732 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1733 * REMOVE are the big ones, since we don't handle administrative installs
1734 * yet anyway.
1736 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1737 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1738 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1740 if (!override)
1742 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1744 BOOL feature_state = ((feature->Level > 0) &&
1745 (feature->Level <= install_level));
1747 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1749 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1750 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1751 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1752 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1753 else
1754 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1758 /* disable child features of unselected parent features */
1759 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1761 FeatureList *fl;
1763 if (feature->Level > 0 && feature->Level <= install_level)
1764 continue;
1766 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1767 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1770 else
1772 /* set the Preselected Property */
1773 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1774 static const WCHAR szOne[] = { '1', 0 };
1776 MSI_SetPropertyW(package,szPreselected,szOne);
1780 * now we want to enable or disable components base on feature
1783 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1785 ComponentList *cl;
1787 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1788 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1790 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1792 component = cl->component;
1794 if (!component->Enabled)
1795 continue;
1797 if (component->Attributes & msidbComponentAttributesOptional)
1798 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1799 else
1801 if (component->Attributes & msidbComponentAttributesSourceOnly)
1802 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1803 else
1804 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1807 if (component->ForceLocalState)
1808 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1810 if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1812 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1813 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1815 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1817 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1818 (component->Action == INSTALLSTATE_ABSENT) ||
1819 (component->Action == INSTALLSTATE_ADVERTISED) ||
1820 (component->Action == INSTALLSTATE_DEFAULT))
1821 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1823 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1825 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1826 (component->Action == INSTALLSTATE_ABSENT))
1827 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1829 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1831 if (component->Action == INSTALLSTATE_UNKNOWN)
1832 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1834 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1835 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1837 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1838 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1842 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1844 if (component->Action == INSTALLSTATE_DEFAULT)
1846 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1847 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1850 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1851 debugstr_w(component->Component), component->Installed, component->Action);
1855 return ERROR_SUCCESS;
1858 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1860 MSIPACKAGE *package = (MSIPACKAGE*)param;
1861 LPCWSTR name;
1862 LPWSTR path;
1864 name = MSI_RecordGetString(row,1);
1866 /* This helper function now does ALL the work */
1867 TRACE("Dir %s ...\n",debugstr_w(name));
1868 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1869 TRACE("resolves to %s\n",debugstr_w(path));
1870 msi_free(path);
1872 return ERROR_SUCCESS;
1875 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1877 MSIPACKAGE *package = (MSIPACKAGE*)param;
1878 LPCWSTR name;
1879 MSIFEATURE *feature;
1881 name = MSI_RecordGetString( row, 1 );
1883 feature = get_loaded_feature( package, name );
1884 if (!feature)
1885 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1886 else
1888 LPCWSTR Condition;
1889 Condition = MSI_RecordGetString(row,3);
1891 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1893 int level = MSI_RecordGetInteger(row,2);
1894 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1895 feature->Level = level;
1898 return ERROR_SUCCESS;
1901 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1903 static const WCHAR name_fmt[] =
1904 {'%','u','.','%','u','.','%','u','.','%','u',0};
1905 static WCHAR name[] = {'\\',0};
1906 VS_FIXEDFILEINFO *lpVer;
1907 WCHAR filever[0x100];
1908 LPVOID version;
1909 DWORD versize;
1910 DWORD handle;
1911 UINT sz;
1913 TRACE("%s\n", debugstr_w(filename));
1915 versize = GetFileVersionInfoSizeW( filename, &handle );
1916 if (!versize)
1917 return NULL;
1919 version = msi_alloc( versize );
1920 GetFileVersionInfoW( filename, 0, versize, version );
1922 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1923 msi_free( version );
1925 sprintfW( filever, name_fmt,
1926 HIWORD(lpVer->dwFileVersionMS),
1927 LOWORD(lpVer->dwFileVersionMS),
1928 HIWORD(lpVer->dwFileVersionLS),
1929 LOWORD(lpVer->dwFileVersionLS));
1931 return strdupW( filever );
1934 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1936 LPWSTR file_version;
1937 MSIFILE *file;
1939 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1941 MSICOMPONENT* comp = file->Component;
1942 LPWSTR p;
1944 if (!comp)
1945 continue;
1947 if (file->IsCompressed)
1948 comp->ForceLocalState = TRUE;
1950 /* calculate target */
1951 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1953 msi_free(file->TargetPath);
1955 TRACE("file %s is named %s\n",
1956 debugstr_w(file->File), debugstr_w(file->FileName));
1958 file->TargetPath = build_directory_name(2, p, file->FileName);
1960 msi_free(p);
1962 TRACE("file %s resolves to %s\n",
1963 debugstr_w(file->File), debugstr_w(file->TargetPath));
1965 /* don't check files of components that aren't installed */
1966 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1967 comp->Installed == INSTALLSTATE_ABSENT)
1969 file->state = msifs_missing; /* assume files are missing */
1970 continue;
1973 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1975 file->state = msifs_missing;
1976 comp->Cost += file->FileSize;
1977 comp->Installed = INSTALLSTATE_INCOMPLETE;
1978 continue;
1981 if (file->Version &&
1982 (file_version = msi_get_disk_file_version( file->TargetPath )))
1984 TRACE("new %s old %s\n", debugstr_w(file->Version),
1985 debugstr_w(file_version));
1986 /* FIXME: seems like a bad way to compare version numbers */
1987 if (lstrcmpiW(file_version, file->Version)<0)
1989 file->state = msifs_overwrite;
1990 comp->Cost += file->FileSize;
1991 comp->Installed = INSTALLSTATE_INCOMPLETE;
1993 else
1994 file->state = msifs_present;
1995 msi_free( file_version );
1997 else
1998 file->state = msifs_present;
2001 return ERROR_SUCCESS;
2005 * A lot is done in this function aside from just the costing.
2006 * The costing needs to be implemented at some point but for now I am going
2007 * to focus on the directory building
2010 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2012 static const WCHAR ExecSeqQuery[] =
2013 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2014 '`','D','i','r','e','c','t','o','r','y','`',0};
2015 static const WCHAR ConditionQuery[] =
2016 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2017 '`','C','o','n','d','i','t','i','o','n','`',0};
2018 static const WCHAR szCosting[] =
2019 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2020 static const WCHAR szlevel[] =
2021 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2022 static const WCHAR szOne[] = { '1', 0 };
2023 MSICOMPONENT *comp;
2024 UINT rc;
2025 MSIQUERY * view;
2026 LPWSTR level;
2028 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2029 return ERROR_SUCCESS;
2031 TRACE("Building Directory properties\n");
2033 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2034 if (rc == ERROR_SUCCESS)
2036 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2037 package);
2038 msiobj_release(&view->hdr);
2041 /* read components states from the registry */
2042 ACTION_GetComponentInstallStates(package);
2044 TRACE("File calculations\n");
2045 msi_check_file_install_states( package );
2047 TRACE("Evaluating Condition Table\n");
2049 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2050 if (rc == ERROR_SUCCESS)
2052 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2053 package);
2054 msiobj_release(&view->hdr);
2057 TRACE("Enabling or Disabling Components\n");
2058 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2060 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2062 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2063 comp->Enabled = FALSE;
2067 MSI_SetPropertyW(package,szCosting,szOne);
2068 /* set default run level if not set */
2069 level = msi_dup_property( package, szlevel );
2070 if (!level)
2071 MSI_SetPropertyW(package,szlevel, szOne);
2072 msi_free(level);
2074 ACTION_UpdateFeatureInstallStates(package);
2076 return MSI_SetFeatureStates(package);
2079 /* OK this value is "interpreted" and then formatted based on the
2080 first few characters */
2081 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2082 DWORD *size)
2084 LPSTR data = NULL;
2085 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2087 if (value[1]=='x')
2089 LPWSTR ptr;
2090 CHAR byte[5];
2091 LPWSTR deformated = NULL;
2092 int count;
2094 deformat_string(package, &value[2], &deformated);
2096 /* binary value type */
2097 ptr = deformated;
2098 *type = REG_BINARY;
2099 if (strlenW(ptr)%2)
2100 *size = (strlenW(ptr)/2)+1;
2101 else
2102 *size = strlenW(ptr)/2;
2104 data = msi_alloc(*size);
2106 byte[0] = '0';
2107 byte[1] = 'x';
2108 byte[4] = 0;
2109 count = 0;
2110 /* if uneven pad with a zero in front */
2111 if (strlenW(ptr)%2)
2113 byte[2]= '0';
2114 byte[3]= *ptr;
2115 ptr++;
2116 data[count] = (BYTE)strtol(byte,NULL,0);
2117 count ++;
2118 TRACE("Uneven byte count\n");
2120 while (*ptr)
2122 byte[2]= *ptr;
2123 ptr++;
2124 byte[3]= *ptr;
2125 ptr++;
2126 data[count] = (BYTE)strtol(byte,NULL,0);
2127 count ++;
2129 msi_free(deformated);
2131 TRACE("Data %i bytes(%i)\n",*size,count);
2133 else
2135 LPWSTR deformated;
2136 LPWSTR p;
2137 DWORD d = 0;
2138 deformat_string(package, &value[1], &deformated);
2140 *type=REG_DWORD;
2141 *size = sizeof(DWORD);
2142 data = msi_alloc(*size);
2143 p = deformated;
2144 if (*p == '-')
2145 p++;
2146 while (*p)
2148 if ( (*p < '0') || (*p > '9') )
2149 break;
2150 d *= 10;
2151 d += (*p - '0');
2152 p++;
2154 if (deformated[0] == '-')
2155 d = -d;
2156 *(LPDWORD)data = d;
2157 TRACE("DWORD %i\n",*(LPDWORD)data);
2159 msi_free(deformated);
2162 else
2164 static const WCHAR szMulti[] = {'[','~',']',0};
2165 LPCWSTR ptr;
2166 *type=REG_SZ;
2168 if (value[0]=='#')
2170 if (value[1]=='%')
2172 ptr = &value[2];
2173 *type=REG_EXPAND_SZ;
2175 else
2176 ptr = &value[1];
2178 else
2179 ptr=value;
2181 if (strstrW(value,szMulti))
2182 *type = REG_MULTI_SZ;
2184 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2186 return data;
2189 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2191 MSIPACKAGE *package = (MSIPACKAGE*)param;
2192 static const WCHAR szHCR[] =
2193 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2194 'R','O','O','T','\\',0};
2195 static const WCHAR szHCU[] =
2196 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2197 'U','S','E','R','\\',0};
2198 static const WCHAR szHLM[] =
2199 {'H','K','E','Y','_','L','O','C','A','L','_',
2200 'M','A','C','H','I','N','E','\\',0};
2201 static const WCHAR szHU[] =
2202 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2204 LPSTR value_data = NULL;
2205 HKEY root_key, hkey;
2206 DWORD type,size;
2207 LPWSTR deformated;
2208 LPCWSTR szRoot, component, name, key, value;
2209 MSICOMPONENT *comp;
2210 MSIRECORD * uirow;
2211 LPWSTR uikey;
2212 INT root;
2213 BOOL check_first = FALSE;
2214 UINT rc;
2216 ui_progress(package,2,0,0,0);
2218 value = NULL;
2219 key = NULL;
2220 uikey = NULL;
2221 name = NULL;
2223 component = MSI_RecordGetString(row, 6);
2224 comp = get_loaded_component(package,component);
2225 if (!comp)
2226 return ERROR_SUCCESS;
2228 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2230 TRACE("Skipping write due to disabled component %s\n",
2231 debugstr_w(component));
2233 comp->Action = comp->Installed;
2235 return ERROR_SUCCESS;
2238 comp->Action = INSTALLSTATE_LOCAL;
2240 name = MSI_RecordGetString(row, 4);
2241 if( MSI_RecordIsNull(row,5) && name )
2243 /* null values can have special meanings */
2244 if (name[0]=='-' && name[1] == 0)
2245 return ERROR_SUCCESS;
2246 else if ((name[0]=='+' && name[1] == 0) ||
2247 (name[0] == '*' && name[1] == 0))
2248 name = NULL;
2249 check_first = TRUE;
2252 root = MSI_RecordGetInteger(row,2);
2253 key = MSI_RecordGetString(row, 3);
2255 /* get the root key */
2256 switch (root)
2258 case -1:
2260 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2261 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2262 if (all_users && all_users[0] == '1')
2264 root_key = HKEY_LOCAL_MACHINE;
2265 szRoot = szHLM;
2267 else
2269 root_key = HKEY_CURRENT_USER;
2270 szRoot = szHCU;
2272 msi_free(all_users);
2274 break;
2275 case 0: root_key = HKEY_CLASSES_ROOT;
2276 szRoot = szHCR;
2277 break;
2278 case 1: root_key = HKEY_CURRENT_USER;
2279 szRoot = szHCU;
2280 break;
2281 case 2: root_key = HKEY_LOCAL_MACHINE;
2282 szRoot = szHLM;
2283 break;
2284 case 3: root_key = HKEY_USERS;
2285 szRoot = szHU;
2286 break;
2287 default:
2288 ERR("Unknown root %i\n",root);
2289 root_key=NULL;
2290 szRoot = NULL;
2291 break;
2293 if (!root_key)
2294 return ERROR_SUCCESS;
2296 deformat_string(package, key , &deformated);
2297 size = strlenW(deformated) + strlenW(szRoot) + 1;
2298 uikey = msi_alloc(size*sizeof(WCHAR));
2299 strcpyW(uikey,szRoot);
2300 strcatW(uikey,deformated);
2302 if (RegCreateKeyW( root_key, deformated, &hkey))
2304 ERR("Could not create key %s\n",debugstr_w(deformated));
2305 msi_free(deformated);
2306 msi_free(uikey);
2307 return ERROR_SUCCESS;
2309 msi_free(deformated);
2311 value = MSI_RecordGetString(row,5);
2312 if (value)
2313 value_data = parse_value(package, value, &type, &size);
2314 else
2316 static const WCHAR szEmpty[] = {0};
2317 value_data = (LPSTR)strdupW(szEmpty);
2318 size = 0;
2319 type = REG_SZ;
2322 deformat_string(package, name, &deformated);
2324 /* get the double nulls to terminate SZ_MULTI */
2325 if (type == REG_MULTI_SZ)
2326 size +=sizeof(WCHAR);
2328 if (!check_first)
2330 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2331 debugstr_w(uikey));
2332 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2334 else
2336 DWORD sz = 0;
2337 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2338 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2340 TRACE("value %s of %s checked already exists\n",
2341 debugstr_w(deformated), debugstr_w(uikey));
2343 else
2345 TRACE("Checked and setting value %s of %s\n",
2346 debugstr_w(deformated), debugstr_w(uikey));
2347 if (deformated || size)
2348 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2351 RegCloseKey(hkey);
2353 uirow = MSI_CreateRecord(3);
2354 MSI_RecordSetStringW(uirow,2,deformated);
2355 MSI_RecordSetStringW(uirow,1,uikey);
2357 if (type == REG_SZ)
2358 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2359 else
2360 MSI_RecordSetStringW(uirow,3,value);
2362 ui_actiondata(package,szWriteRegistryValues,uirow);
2363 msiobj_release( &uirow->hdr );
2365 msi_free(value_data);
2366 msi_free(deformated);
2367 msi_free(uikey);
2369 return ERROR_SUCCESS;
2372 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2374 UINT rc;
2375 MSIQUERY * view;
2376 static const WCHAR ExecSeqQuery[] =
2377 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2378 '`','R','e','g','i','s','t','r','y','`',0 };
2380 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2381 if (rc != ERROR_SUCCESS)
2382 return ERROR_SUCCESS;
2384 /* increment progress bar each time action data is sent */
2385 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2387 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2389 msiobj_release(&view->hdr);
2390 return rc;
2393 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2395 package->script->CurrentlyScripting = TRUE;
2397 return ERROR_SUCCESS;
2401 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2403 MSICOMPONENT *comp;
2404 DWORD progress = 0;
2405 DWORD total = 0;
2406 static const WCHAR q1[]=
2407 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2408 '`','R','e','g','i','s','t','r','y','`',0};
2409 UINT rc;
2410 MSIQUERY * view;
2411 MSIFEATURE *feature;
2412 MSIFILE *file;
2414 TRACE("InstallValidate\n");
2416 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2417 if (rc == ERROR_SUCCESS)
2419 MSI_IterateRecords( view, &progress, NULL, package );
2420 msiobj_release( &view->hdr );
2421 total += progress * REG_PROGRESS_VALUE;
2424 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2425 total += COMPONENT_PROGRESS_VALUE;
2427 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2428 total += file->FileSize;
2430 ui_progress(package,0,total,0,0);
2432 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2434 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2435 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2436 feature->ActionRequest);
2439 return ERROR_SUCCESS;
2442 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2444 MSIPACKAGE* package = (MSIPACKAGE*)param;
2445 LPCWSTR cond = NULL;
2446 LPCWSTR message = NULL;
2447 static const WCHAR title[]=
2448 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2450 cond = MSI_RecordGetString(row,1);
2452 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2454 LPWSTR deformated;
2455 message = MSI_RecordGetString(row,2);
2456 deformat_string(package,message,&deformated);
2457 MessageBoxW(NULL,deformated,title,MB_OK);
2458 msi_free(deformated);
2459 return ERROR_FUNCTION_FAILED;
2462 return ERROR_SUCCESS;
2465 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2467 UINT rc;
2468 MSIQUERY * view = NULL;
2469 static const WCHAR ExecSeqQuery[] =
2470 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2471 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2473 TRACE("Checking launch conditions\n");
2475 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2476 if (rc != ERROR_SUCCESS)
2477 return ERROR_SUCCESS;
2479 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2480 msiobj_release(&view->hdr);
2482 return rc;
2485 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2488 if (!cmp->KeyPath)
2489 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2491 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2493 MSIRECORD * row = 0;
2494 UINT root,len;
2495 LPWSTR deformated,buffer,deformated_name;
2496 LPCWSTR key,name;
2497 static const WCHAR ExecSeqQuery[] =
2498 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2499 '`','R','e','g','i','s','t','r','y','`',' ',
2500 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2501 ' ','=',' ' ,'\'','%','s','\'',0 };
2502 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2503 static const WCHAR fmt2[]=
2504 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2506 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2507 if (!row)
2508 return NULL;
2510 root = MSI_RecordGetInteger(row,2);
2511 key = MSI_RecordGetString(row, 3);
2512 name = MSI_RecordGetString(row, 4);
2513 deformat_string(package, key , &deformated);
2514 deformat_string(package, name, &deformated_name);
2516 len = strlenW(deformated) + 6;
2517 if (deformated_name)
2518 len+=strlenW(deformated_name);
2520 buffer = msi_alloc( len *sizeof(WCHAR));
2522 if (deformated_name)
2523 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2524 else
2525 sprintfW(buffer,fmt,root,deformated);
2527 msi_free(deformated);
2528 msi_free(deformated_name);
2529 msiobj_release(&row->hdr);
2531 return buffer;
2533 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2535 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2536 return NULL;
2538 else
2540 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2542 if (file)
2543 return strdupW( file->TargetPath );
2545 return NULL;
2548 static HKEY openSharedDLLsKey(void)
2550 HKEY hkey=0;
2551 static const WCHAR path[] =
2552 {'S','o','f','t','w','a','r','e','\\',
2553 'M','i','c','r','o','s','o','f','t','\\',
2554 'W','i','n','d','o','w','s','\\',
2555 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2556 'S','h','a','r','e','d','D','L','L','s',0};
2558 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2559 return hkey;
2562 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2564 HKEY hkey;
2565 DWORD count=0;
2566 DWORD type;
2567 DWORD sz = sizeof(count);
2568 DWORD rc;
2570 hkey = openSharedDLLsKey();
2571 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2572 if (rc != ERROR_SUCCESS)
2573 count = 0;
2574 RegCloseKey(hkey);
2575 return count;
2578 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2580 HKEY hkey;
2582 hkey = openSharedDLLsKey();
2583 if (count > 0)
2584 msi_reg_set_val_dword( hkey, path, count );
2585 else
2586 RegDeleteValueW(hkey,path);
2587 RegCloseKey(hkey);
2588 return count;
2592 * Return TRUE if the count should be written out and FALSE if not
2594 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2596 MSIFEATURE *feature;
2597 INT count = 0;
2598 BOOL write = FALSE;
2600 /* only refcount DLLs */
2601 if (comp->KeyPath == NULL ||
2602 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2603 comp->Attributes & msidbComponentAttributesODBCDataSource)
2604 write = FALSE;
2605 else
2607 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2608 write = (count > 0);
2610 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2611 write = TRUE;
2614 /* increment counts */
2615 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2617 ComponentList *cl;
2619 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2620 continue;
2622 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2624 if ( cl->component == comp )
2625 count++;
2629 /* decrement counts */
2630 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2632 ComponentList *cl;
2634 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2635 continue;
2637 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2639 if ( cl->component == comp )
2640 count--;
2644 /* ref count all the files in the component */
2645 if (write)
2647 MSIFILE *file;
2649 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2651 if (file->Component == comp)
2652 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2656 /* add a count for permenent */
2657 if (comp->Attributes & msidbComponentAttributesPermanent)
2658 count ++;
2660 comp->RefCount = count;
2662 if (write)
2663 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2667 * Ok further analysis makes me think that this work is
2668 * actually done in the PublishComponents and PublishFeatures
2669 * step, and not here. It appears like the keypath and all that is
2670 * resolved in this step, however actually written in the Publish steps.
2671 * But we will leave it here for now because it is unclear
2673 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2675 WCHAR squished_pc[GUID_SIZE];
2676 WCHAR squished_cc[GUID_SIZE];
2677 UINT rc;
2678 MSICOMPONENT *comp;
2679 HKEY hkey=0,hkey2=0;
2681 /* writes the Component and Features values to the registry */
2683 rc = MSIREG_OpenComponents(&hkey);
2684 if (rc != ERROR_SUCCESS)
2685 return rc;
2687 squash_guid(package->ProductCode,squished_pc);
2688 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2690 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2692 MSIRECORD * uirow;
2694 ui_progress(package,2,0,0,0);
2695 if (!comp->ComponentId)
2696 continue;
2698 squash_guid(comp->ComponentId,squished_cc);
2700 msi_free(comp->FullKeypath);
2701 comp->FullKeypath = resolve_keypath( package, comp );
2703 /* do the refcounting */
2704 ACTION_RefCountComponent( package, comp );
2706 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2707 debugstr_w(comp->Component),
2708 debugstr_w(squished_cc),
2709 debugstr_w(comp->FullKeypath),
2710 comp->RefCount);
2712 * Write the keypath out if the component is to be registered
2713 * and delete the key if the component is to be deregistered
2715 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2717 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2718 if (rc != ERROR_SUCCESS)
2719 continue;
2721 if (!comp->FullKeypath)
2722 continue;
2724 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2726 if (comp->Attributes & msidbComponentAttributesPermanent)
2728 static const WCHAR szPermKey[] =
2729 { '0','0','0','0','0','0','0','0','0','0','0','0',
2730 '0','0','0','0','0','0','0','0','0','0','0','0',
2731 '0','0','0','0','0','0','0','0',0 };
2733 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2736 RegCloseKey(hkey2);
2738 /* UI stuff */
2739 uirow = MSI_CreateRecord(3);
2740 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2741 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2742 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2743 ui_actiondata(package,szProcessComponents,uirow);
2744 msiobj_release( &uirow->hdr );
2746 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2748 DWORD res;
2750 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2751 if (rc != ERROR_SUCCESS)
2752 continue;
2754 RegDeleteValueW(hkey2,squished_pc);
2756 /* if the key is empty delete it */
2757 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2758 RegCloseKey(hkey2);
2759 if (res == ERROR_NO_MORE_ITEMS)
2760 RegDeleteKeyW(hkey,squished_cc);
2762 /* UI stuff */
2763 uirow = MSI_CreateRecord(2);
2764 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2765 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2766 ui_actiondata(package,szProcessComponents,uirow);
2767 msiobj_release( &uirow->hdr );
2770 RegCloseKey(hkey);
2771 return rc;
2774 typedef struct {
2775 CLSID clsid;
2776 LPWSTR source;
2778 LPWSTR path;
2779 ITypeLib *ptLib;
2780 } typelib_struct;
2782 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2783 LPWSTR lpszName, LONG_PTR lParam)
2785 TLIBATTR *attr;
2786 typelib_struct *tl_struct = (typelib_struct*) lParam;
2787 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2788 int sz;
2789 HRESULT res;
2791 if (!IS_INTRESOURCE(lpszName))
2793 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2794 return TRUE;
2797 sz = strlenW(tl_struct->source)+4;
2798 sz *= sizeof(WCHAR);
2800 if ((INT_PTR)lpszName == 1)
2801 tl_struct->path = strdupW(tl_struct->source);
2802 else
2804 tl_struct->path = msi_alloc(sz);
2805 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2808 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2809 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2810 if (!SUCCEEDED(res))
2812 msi_free(tl_struct->path);
2813 tl_struct->path = NULL;
2815 return TRUE;
2818 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2819 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2821 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2822 return FALSE;
2825 msi_free(tl_struct->path);
2826 tl_struct->path = NULL;
2828 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2829 ITypeLib_Release(tl_struct->ptLib);
2831 return TRUE;
2834 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2836 MSIPACKAGE* package = (MSIPACKAGE*)param;
2837 LPCWSTR component;
2838 MSICOMPONENT *comp;
2839 MSIFILE *file;
2840 typelib_struct tl_struct;
2841 HMODULE module;
2842 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2844 component = MSI_RecordGetString(row,3);
2845 comp = get_loaded_component(package,component);
2846 if (!comp)
2847 return ERROR_SUCCESS;
2849 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2851 TRACE("Skipping typelib reg due to disabled component\n");
2853 comp->Action = comp->Installed;
2855 return ERROR_SUCCESS;
2858 comp->Action = INSTALLSTATE_LOCAL;
2860 file = get_loaded_file( package, comp->KeyPath );
2861 if (!file)
2862 return ERROR_SUCCESS;
2864 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2865 if (module)
2867 LPCWSTR guid;
2868 guid = MSI_RecordGetString(row,1);
2869 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2870 tl_struct.source = strdupW( file->TargetPath );
2871 tl_struct.path = NULL;
2873 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2874 (LONG_PTR)&tl_struct);
2876 if (tl_struct.path)
2878 LPWSTR help = NULL;
2879 LPCWSTR helpid;
2880 HRESULT res;
2882 helpid = MSI_RecordGetString(row,6);
2884 if (helpid)
2885 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2886 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2887 msi_free(help);
2889 if (!SUCCEEDED(res))
2890 ERR("Failed to register type library %s\n",
2891 debugstr_w(tl_struct.path));
2892 else
2894 ui_actiondata(package,szRegisterTypeLibraries,row);
2896 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2899 ITypeLib_Release(tl_struct.ptLib);
2900 msi_free(tl_struct.path);
2902 else
2903 ERR("Failed to load type library %s\n",
2904 debugstr_w(tl_struct.source));
2906 FreeLibrary(module);
2907 msi_free(tl_struct.source);
2909 else
2910 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2912 return ERROR_SUCCESS;
2915 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2918 * OK this is a bit confusing.. I am given a _Component key and I believe
2919 * that the file that is being registered as a type library is the "key file
2920 * of that component" which I interpret to mean "The file in the KeyPath of
2921 * that component".
2923 UINT rc;
2924 MSIQUERY * view;
2925 static const WCHAR Query[] =
2926 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2927 '`','T','y','p','e','L','i','b','`',0};
2929 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2930 if (rc != ERROR_SUCCESS)
2931 return ERROR_SUCCESS;
2933 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2934 msiobj_release(&view->hdr);
2935 return rc;
2938 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2940 MSIPACKAGE *package = (MSIPACKAGE*)param;
2941 LPWSTR target_file, target_folder, filename;
2942 LPCWSTR buffer, extension;
2943 MSICOMPONENT *comp;
2944 static const WCHAR szlnk[]={'.','l','n','k',0};
2945 IShellLinkW *sl = NULL;
2946 IPersistFile *pf = NULL;
2947 HRESULT res;
2949 buffer = MSI_RecordGetString(row,4);
2950 comp = get_loaded_component(package,buffer);
2951 if (!comp)
2952 return ERROR_SUCCESS;
2954 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2956 TRACE("Skipping shortcut creation due to disabled component\n");
2958 comp->Action = comp->Installed;
2960 return ERROR_SUCCESS;
2963 comp->Action = INSTALLSTATE_LOCAL;
2965 ui_actiondata(package,szCreateShortcuts,row);
2967 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2968 &IID_IShellLinkW, (LPVOID *) &sl );
2970 if (FAILED( res ))
2972 ERR("CLSID_ShellLink not available\n");
2973 goto err;
2976 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2977 if (FAILED( res ))
2979 ERR("QueryInterface(IID_IPersistFile) failed\n");
2980 goto err;
2983 buffer = MSI_RecordGetString(row,2);
2984 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2986 /* may be needed because of a bug somehwere else */
2987 create_full_pathW(target_folder);
2989 filename = msi_dup_record_field( row, 3 );
2990 reduce_to_longfilename(filename);
2992 extension = strchrW(filename,'.');
2993 if (!extension || strcmpiW(extension,szlnk))
2995 int len = strlenW(filename);
2996 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2997 memcpy(filename + len, szlnk, sizeof(szlnk));
2999 target_file = build_directory_name(2, target_folder, filename);
3000 msi_free(target_folder);
3001 msi_free(filename);
3003 buffer = MSI_RecordGetString(row,5);
3004 if (strchrW(buffer,'['))
3006 LPWSTR deformated;
3007 deformat_string(package,buffer,&deformated);
3008 IShellLinkW_SetPath(sl,deformated);
3009 msi_free(deformated);
3011 else
3013 FIXME("poorly handled shortcut format, advertised shortcut\n");
3014 IShellLinkW_SetPath(sl,comp->FullKeypath);
3017 if (!MSI_RecordIsNull(row,6))
3019 LPWSTR deformated;
3020 buffer = MSI_RecordGetString(row,6);
3021 deformat_string(package,buffer,&deformated);
3022 IShellLinkW_SetArguments(sl,deformated);
3023 msi_free(deformated);
3026 if (!MSI_RecordIsNull(row,7))
3028 buffer = MSI_RecordGetString(row,7);
3029 IShellLinkW_SetDescription(sl,buffer);
3032 if (!MSI_RecordIsNull(row,8))
3033 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3035 if (!MSI_RecordIsNull(row,9))
3037 LPWSTR Path;
3038 INT index;
3040 buffer = MSI_RecordGetString(row,9);
3042 Path = build_icon_path(package,buffer);
3043 index = MSI_RecordGetInteger(row,10);
3045 /* no value means 0 */
3046 if (index == MSI_NULL_INTEGER)
3047 index = 0;
3049 IShellLinkW_SetIconLocation(sl,Path,index);
3050 msi_free(Path);
3053 if (!MSI_RecordIsNull(row,11))
3054 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3056 if (!MSI_RecordIsNull(row,12))
3058 LPWSTR Path;
3059 buffer = MSI_RecordGetString(row,12);
3060 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3061 if (Path)
3062 IShellLinkW_SetWorkingDirectory(sl,Path);
3063 msi_free(Path);
3066 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3067 IPersistFile_Save(pf,target_file,FALSE);
3069 msi_free(target_file);
3071 err:
3072 if (pf)
3073 IPersistFile_Release( pf );
3074 if (sl)
3075 IShellLinkW_Release( sl );
3077 return ERROR_SUCCESS;
3080 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3082 UINT rc;
3083 HRESULT res;
3084 MSIQUERY * view;
3085 static const WCHAR Query[] =
3086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3087 '`','S','h','o','r','t','c','u','t','`',0};
3089 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3090 if (rc != ERROR_SUCCESS)
3091 return ERROR_SUCCESS;
3093 res = CoInitialize( NULL );
3094 if (FAILED (res))
3096 ERR("CoInitialize failed\n");
3097 return ERROR_FUNCTION_FAILED;
3100 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3101 msiobj_release(&view->hdr);
3103 CoUninitialize();
3105 return rc;
3108 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3110 MSIPACKAGE* package = (MSIPACKAGE*)param;
3111 HANDLE the_file;
3112 LPWSTR FilePath;
3113 LPCWSTR FileName;
3114 CHAR buffer[1024];
3115 DWORD sz;
3116 UINT rc;
3117 MSIRECORD *uirow;
3119 FileName = MSI_RecordGetString(row,1);
3120 if (!FileName)
3122 ERR("Unable to get FileName\n");
3123 return ERROR_SUCCESS;
3126 FilePath = build_icon_path(package,FileName);
3128 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3130 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3131 FILE_ATTRIBUTE_NORMAL, NULL);
3133 if (the_file == INVALID_HANDLE_VALUE)
3135 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3136 msi_free(FilePath);
3137 return ERROR_SUCCESS;
3142 DWORD write;
3143 sz = 1024;
3144 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3145 if (rc != ERROR_SUCCESS)
3147 ERR("Failed to get stream\n");
3148 CloseHandle(the_file);
3149 DeleteFileW(FilePath);
3150 break;
3152 WriteFile(the_file,buffer,sz,&write,NULL);
3153 } while (sz == 1024);
3155 msi_free(FilePath);
3157 CloseHandle(the_file);
3159 uirow = MSI_CreateRecord(1);
3160 MSI_RecordSetStringW(uirow,1,FileName);
3161 ui_actiondata(package,szPublishProduct,uirow);
3162 msiobj_release( &uirow->hdr );
3164 return ERROR_SUCCESS;
3168 * 99% of the work done here is only done for
3169 * advertised installs. However this is where the
3170 * Icon table is processed and written out
3171 * so that is what I am going to do here.
3173 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3175 UINT rc;
3176 MSIQUERY * view;
3177 static const WCHAR Query[]=
3178 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3179 '`','I','c','o','n','`',0};
3180 /* for registry stuff */
3181 HKEY hkey=0;
3182 HKEY hukey=0;
3183 static const WCHAR szProductLanguage[] =
3184 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3185 static const WCHAR szARPProductIcon[] =
3186 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3187 static const WCHAR szProductVersion[] =
3188 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3189 DWORD langid;
3190 LPWSTR buffer;
3191 DWORD size;
3192 MSIHANDLE hDb, hSumInfo;
3194 /* write out icon files */
3196 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3197 if (rc == ERROR_SUCCESS)
3199 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3200 msiobj_release(&view->hdr);
3203 /* ok there is a lot more done here but i need to figure out what */
3205 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3206 if (rc != ERROR_SUCCESS)
3207 goto end;
3209 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3210 if (rc != ERROR_SUCCESS)
3211 goto end;
3214 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3215 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3216 msi_free(buffer);
3218 langid = msi_get_property_int( package, szProductLanguage, 0 );
3219 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3221 buffer = msi_dup_property( package, szARPProductIcon );
3222 if (buffer)
3224 LPWSTR path = build_icon_path(package,buffer);
3225 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3226 msi_free( path );
3228 msi_free(buffer);
3230 buffer = msi_dup_property( package, szProductVersion );
3231 if (buffer)
3233 DWORD verdword = msi_version_str_to_dword(buffer);
3234 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3236 msi_free(buffer);
3238 /* FIXME: Need to write more keys to the user registry */
3240 hDb= alloc_msihandle( &package->db->hdr );
3241 if (!hDb) {
3242 rc = ERROR_NOT_ENOUGH_MEMORY;
3243 goto end;
3245 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3246 MsiCloseHandle(hDb);
3247 if (rc == ERROR_SUCCESS)
3249 WCHAR guidbuffer[0x200];
3250 size = 0x200;
3251 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3252 guidbuffer, &size);
3253 if (rc == ERROR_SUCCESS)
3255 WCHAR squashed[GUID_SIZE];
3256 /* for now we only care about the first guid */
3257 LPWSTR ptr = strchrW(guidbuffer,';');
3258 if (ptr) *ptr = 0;
3259 squash_guid(guidbuffer,squashed);
3260 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3262 else
3264 ERR("Unable to query Revision_Number...\n");
3265 rc = ERROR_SUCCESS;
3267 MsiCloseHandle(hSumInfo);
3269 else
3271 ERR("Unable to open Summary Information\n");
3272 rc = ERROR_SUCCESS;
3275 end:
3277 RegCloseKey(hkey);
3278 RegCloseKey(hukey);
3280 return rc;
3283 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3285 MSIPACKAGE *package = (MSIPACKAGE*)param;
3286 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3287 LPWSTR deformated_section, deformated_key, deformated_value;
3288 LPWSTR folder, fullname = NULL;
3289 MSIRECORD * uirow;
3290 INT action;
3291 MSICOMPONENT *comp;
3292 static const WCHAR szWindowsFolder[] =
3293 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3295 component = MSI_RecordGetString(row, 8);
3296 comp = get_loaded_component(package,component);
3298 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3300 TRACE("Skipping ini file due to disabled component %s\n",
3301 debugstr_w(component));
3303 comp->Action = comp->Installed;
3305 return ERROR_SUCCESS;
3308 comp->Action = INSTALLSTATE_LOCAL;
3310 identifier = MSI_RecordGetString(row,1);
3311 filename = MSI_RecordGetString(row,2);
3312 dirproperty = MSI_RecordGetString(row,3);
3313 section = MSI_RecordGetString(row,4);
3314 key = MSI_RecordGetString(row,5);
3315 value = MSI_RecordGetString(row,6);
3316 action = MSI_RecordGetInteger(row,7);
3318 deformat_string(package,section,&deformated_section);
3319 deformat_string(package,key,&deformated_key);
3320 deformat_string(package,value,&deformated_value);
3322 if (dirproperty)
3324 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3325 if (!folder)
3326 folder = msi_dup_property( package, dirproperty );
3328 else
3329 folder = msi_dup_property( package, szWindowsFolder );
3331 if (!folder)
3333 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3334 goto cleanup;
3337 fullname = build_directory_name(2, folder, filename);
3339 if (action == 0)
3341 TRACE("Adding value %s to section %s in %s\n",
3342 debugstr_w(deformated_key), debugstr_w(deformated_section),
3343 debugstr_w(fullname));
3344 WritePrivateProfileStringW(deformated_section, deformated_key,
3345 deformated_value, fullname);
3347 else if (action == 1)
3349 WCHAR returned[10];
3350 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3351 returned, 10, fullname);
3352 if (returned[0] == 0)
3354 TRACE("Adding value %s to section %s in %s\n",
3355 debugstr_w(deformated_key), debugstr_w(deformated_section),
3356 debugstr_w(fullname));
3358 WritePrivateProfileStringW(deformated_section, deformated_key,
3359 deformated_value, fullname);
3362 else if (action == 3)
3363 FIXME("Append to existing section not yet implemented\n");
3365 uirow = MSI_CreateRecord(4);
3366 MSI_RecordSetStringW(uirow,1,identifier);
3367 MSI_RecordSetStringW(uirow,2,deformated_section);
3368 MSI_RecordSetStringW(uirow,3,deformated_key);
3369 MSI_RecordSetStringW(uirow,4,deformated_value);
3370 ui_actiondata(package,szWriteIniValues,uirow);
3371 msiobj_release( &uirow->hdr );
3372 cleanup:
3373 msi_free(fullname);
3374 msi_free(folder);
3375 msi_free(deformated_key);
3376 msi_free(deformated_value);
3377 msi_free(deformated_section);
3378 return ERROR_SUCCESS;
3381 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3383 UINT rc;
3384 MSIQUERY * view;
3385 static const WCHAR ExecSeqQuery[] =
3386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3387 '`','I','n','i','F','i','l','e','`',0};
3389 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3390 if (rc != ERROR_SUCCESS)
3392 TRACE("no IniFile table\n");
3393 return ERROR_SUCCESS;
3396 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3397 msiobj_release(&view->hdr);
3398 return rc;
3401 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3403 MSIPACKAGE *package = (MSIPACKAGE*)param;
3404 LPCWSTR filename;
3405 LPWSTR FullName;
3406 MSIFILE *file;
3407 DWORD len;
3408 static const WCHAR ExeStr[] =
3409 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3410 static const WCHAR close[] = {'\"',0};
3411 STARTUPINFOW si;
3412 PROCESS_INFORMATION info;
3413 BOOL brc;
3414 MSIRECORD *uirow;
3415 LPWSTR uipath, p;
3417 memset(&si,0,sizeof(STARTUPINFOW));
3419 filename = MSI_RecordGetString(row,1);
3420 file = get_loaded_file( package, filename );
3422 if (!file)
3424 ERR("Unable to find file id %s\n",debugstr_w(filename));
3425 return ERROR_SUCCESS;
3428 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3430 FullName = msi_alloc(len*sizeof(WCHAR));
3431 strcpyW(FullName,ExeStr);
3432 strcatW( FullName, file->TargetPath );
3433 strcatW(FullName,close);
3435 TRACE("Registering %s\n",debugstr_w(FullName));
3436 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3437 &si, &info);
3439 if (brc)
3440 msi_dialog_check_messages(info.hProcess);
3442 msi_free(FullName);
3444 /* the UI chunk */
3445 uirow = MSI_CreateRecord( 2 );
3446 uipath = strdupW( file->TargetPath );
3447 p = strrchrW(uipath,'\\');
3448 if (p)
3449 p[1]=0;
3450 MSI_RecordSetStringW( uirow, 1, &p[2] );
3451 MSI_RecordSetStringW( uirow, 2, uipath);
3452 ui_actiondata( package, szSelfRegModules, uirow);
3453 msiobj_release( &uirow->hdr );
3454 msi_free( uipath );
3455 /* FIXME: call ui_progress? */
3457 return ERROR_SUCCESS;
3460 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3462 UINT rc;
3463 MSIQUERY * view;
3464 static const WCHAR ExecSeqQuery[] =
3465 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3466 '`','S','e','l','f','R','e','g','`',0};
3468 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3469 if (rc != ERROR_SUCCESS)
3471 TRACE("no SelfReg table\n");
3472 return ERROR_SUCCESS;
3475 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3476 msiobj_release(&view->hdr);
3478 return ERROR_SUCCESS;
3481 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3483 MSIFEATURE *feature;
3484 UINT rc;
3485 HKEY hkey=0;
3486 HKEY hukey=0;
3488 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3489 if (rc != ERROR_SUCCESS)
3490 goto end;
3492 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3493 if (rc != ERROR_SUCCESS)
3494 goto end;
3496 /* here the guids are base 85 encoded */
3497 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3499 ComponentList *cl;
3500 LPWSTR data = NULL;
3501 GUID clsid;
3502 INT size;
3503 BOOL absent = FALSE;
3504 MSIRECORD *uirow;
3506 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3507 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3508 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3509 absent = TRUE;
3511 size = 1;
3512 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3514 size += 21;
3516 if (feature->Feature_Parent)
3517 size += strlenW( feature->Feature_Parent )+2;
3519 data = msi_alloc(size * sizeof(WCHAR));
3521 data[0] = 0;
3522 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3524 MSICOMPONENT* component = cl->component;
3525 WCHAR buf[21];
3527 buf[0] = 0;
3528 if (component->ComponentId)
3530 TRACE("From %s\n",debugstr_w(component->ComponentId));
3531 CLSIDFromString(component->ComponentId, &clsid);
3532 encode_base85_guid(&clsid,buf);
3533 TRACE("to %s\n",debugstr_w(buf));
3534 strcatW(data,buf);
3537 if (feature->Feature_Parent)
3539 static const WCHAR sep[] = {'\2',0};
3540 strcatW(data,sep);
3541 strcatW(data,feature->Feature_Parent);
3544 msi_reg_set_val_str( hkey, feature->Feature, data );
3545 msi_free(data);
3547 size = 0;
3548 if (feature->Feature_Parent)
3549 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3550 if (!absent)
3552 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3553 (LPBYTE)feature->Feature_Parent,size);
3555 else
3557 size += 2*sizeof(WCHAR);
3558 data = msi_alloc(size);
3559 data[0] = 0x6;
3560 data[1] = 0;
3561 if (feature->Feature_Parent)
3562 strcpyW( &data[1], feature->Feature_Parent );
3563 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3564 (LPBYTE)data,size);
3565 msi_free(data);
3568 /* the UI chunk */
3569 uirow = MSI_CreateRecord( 1 );
3570 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3571 ui_actiondata( package, szPublishFeatures, uirow);
3572 msiobj_release( &uirow->hdr );
3573 /* FIXME: call ui_progress? */
3576 end:
3577 RegCloseKey(hkey);
3578 RegCloseKey(hukey);
3579 return rc;
3582 static UINT msi_get_local_package_name( LPWSTR path )
3584 static const WCHAR szInstaller[] = {
3585 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3586 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3587 DWORD time, len, i;
3588 HANDLE handle;
3590 time = GetTickCount();
3591 GetWindowsDirectoryW( path, MAX_PATH );
3592 lstrcatW( path, szInstaller );
3593 CreateDirectoryW( path, NULL );
3595 len = lstrlenW(path);
3596 for (i=0; i<0x10000; i++)
3598 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3599 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3600 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3601 if (handle != INVALID_HANDLE_VALUE)
3603 CloseHandle(handle);
3604 break;
3606 if (GetLastError() != ERROR_FILE_EXISTS &&
3607 GetLastError() != ERROR_SHARING_VIOLATION)
3608 return ERROR_FUNCTION_FAILED;
3611 return ERROR_SUCCESS;
3614 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3616 static const WCHAR szOriginalDatabase[] =
3617 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3618 WCHAR packagefile[MAX_PATH];
3619 LPWSTR msiFilePath;
3620 UINT r;
3622 r = msi_get_local_package_name( packagefile );
3623 if (r != ERROR_SUCCESS)
3624 return r;
3626 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3628 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3629 r = CopyFileW( msiFilePath, packagefile, FALSE);
3630 msi_free( msiFilePath );
3632 if (!r)
3634 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3635 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3636 return ERROR_FUNCTION_FAILED;
3639 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3640 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3641 return ERROR_SUCCESS;
3644 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3646 LPWSTR prop, val, key;
3647 static const LPCSTR propval[] = {
3648 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3649 "ARPCONTACT", "Contact",
3650 "ARPCOMMENTS", "Comments",
3651 "ProductName", "DisplayName",
3652 "ProductVersion", "DisplayVersion",
3653 "ARPHELPLINK", "HelpLink",
3654 "ARPHELPTELEPHONE", "HelpTelephone",
3655 "ARPINSTALLLOCATION", "InstallLocation",
3656 "SourceDir", "InstallSource",
3657 "Manufacturer", "Publisher",
3658 "ARPREADME", "Readme",
3659 "ARPSIZE", "Size",
3660 "ARPURLINFOABOUT", "URLInfoAbout",
3661 "ARPURLUPDATEINFO", "URLUpdateInfo",
3662 NULL,
3664 const LPCSTR *p = propval;
3666 while( *p )
3668 prop = strdupAtoW( *p++ );
3669 key = strdupAtoW( *p++ );
3670 val = msi_dup_property( package, prop );
3671 msi_reg_set_val_str( hkey, key, val );
3672 msi_free(val);
3673 msi_free(key);
3674 msi_free(prop);
3676 return ERROR_SUCCESS;
3679 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3681 HKEY hkey=0;
3682 LPWSTR buffer = NULL;
3683 UINT rc;
3684 DWORD size, langid;
3685 static const WCHAR szWindowsInstaller[] =
3686 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3687 static const WCHAR szUpgradeCode[] =
3688 {'U','p','g','r','a','d','e','C','o','d','e',0};
3689 static const WCHAR modpath_fmt[] =
3690 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3691 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3692 static const WCHAR szModifyPath[] =
3693 {'M','o','d','i','f','y','P','a','t','h',0};
3694 static const WCHAR szUninstallString[] =
3695 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3696 static const WCHAR szEstimatedSize[] =
3697 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3698 static const WCHAR szProductLanguage[] =
3699 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3700 static const WCHAR szProductVersion[] =
3701 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3703 SYSTEMTIME systime;
3704 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3705 LPWSTR upgrade_code;
3706 WCHAR szDate[9];
3708 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3709 if (rc != ERROR_SUCCESS)
3710 return rc;
3712 /* dump all the info i can grab */
3713 /* FIXME: Flesh out more information */
3715 msi_write_uninstall_property_vals( package, hkey );
3717 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3719 msi_make_package_local( package, hkey );
3721 /* do ModifyPath and UninstallString */
3722 size = deformat_string(package,modpath_fmt,&buffer);
3723 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3724 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3725 msi_free(buffer);
3727 /* FIXME: Write real Estimated Size when we have it */
3728 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3730 GetLocalTime(&systime);
3731 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3732 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3734 langid = msi_get_property_int( package, szProductLanguage, 0 );
3735 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3737 buffer = msi_dup_property( package, szProductVersion );
3738 if (buffer)
3740 DWORD verdword = msi_version_str_to_dword(buffer);
3742 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3743 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3744 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3746 msi_free(buffer);
3748 /* Handle Upgrade Codes */
3749 upgrade_code = msi_dup_property( package, szUpgradeCode );
3750 if (upgrade_code)
3752 HKEY hkey2;
3753 WCHAR squashed[33];
3754 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3755 squash_guid(package->ProductCode,squashed);
3756 msi_reg_set_val_str( hkey2, squashed, NULL );
3757 RegCloseKey(hkey2);
3758 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3759 squash_guid(package->ProductCode,squashed);
3760 msi_reg_set_val_str( hkey2, squashed, NULL );
3761 RegCloseKey(hkey2);
3763 msi_free(upgrade_code);
3766 RegCloseKey(hkey);
3768 /* FIXME: call ui_actiondata */
3770 return ERROR_SUCCESS;
3773 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3775 return execute_script(package,INSTALL_SCRIPT);
3778 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3780 UINT rc;
3782 /* turn off scheduling */
3783 package->script->CurrentlyScripting= FALSE;
3785 /* first do the same as an InstallExecute */
3786 rc = ACTION_InstallExecute(package);
3787 if (rc != ERROR_SUCCESS)
3788 return rc;
3790 /* then handle Commit Actions */
3791 rc = execute_script(package,COMMIT_SCRIPT);
3793 return rc;
3796 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3798 static const WCHAR RunOnce[] = {
3799 'S','o','f','t','w','a','r','e','\\',
3800 'M','i','c','r','o','s','o','f','t','\\',
3801 'W','i','n','d','o','w','s','\\',
3802 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3803 'R','u','n','O','n','c','e',0};
3804 static const WCHAR InstallRunOnce[] = {
3805 'S','o','f','t','w','a','r','e','\\',
3806 'M','i','c','r','o','s','o','f','t','\\',
3807 'W','i','n','d','o','w','s','\\',
3808 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3809 'I','n','s','t','a','l','l','e','r','\\',
3810 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3812 static const WCHAR msiexec_fmt[] = {
3813 '%','s',
3814 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3815 '\"','%','s','\"',0};
3816 static const WCHAR install_fmt[] = {
3817 '/','I',' ','\"','%','s','\"',' ',
3818 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3819 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3820 WCHAR buffer[256], sysdir[MAX_PATH];
3821 HKEY hkey;
3822 WCHAR squished_pc[100];
3824 squash_guid(package->ProductCode,squished_pc);
3826 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3827 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3828 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3829 squished_pc);
3831 msi_reg_set_val_str( hkey, squished_pc, buffer );
3832 RegCloseKey(hkey);
3834 TRACE("Reboot command %s\n",debugstr_w(buffer));
3836 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3837 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3839 msi_reg_set_val_str( hkey, squished_pc, buffer );
3840 RegCloseKey(hkey);
3842 return ERROR_INSTALL_SUSPEND;
3845 UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3847 LPWSTR p, source;
3848 DWORD len;
3850 p = strrchrW( package->PackagePath, '\\' );
3851 if (!p)
3852 return ERROR_SUCCESS;
3854 len = p - package->PackagePath + 2;
3855 source = msi_alloc( len * sizeof(WCHAR) );
3856 lstrcpynW( source, package->PackagePath, len );
3858 MSI_SetPropertyW( package, cszSourceDir, source );
3859 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3861 msi_free( source );
3863 return ERROR_SUCCESS;
3866 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3868 DWORD attrib;
3869 UINT rc;
3872 * We are currently doing what should be done here in the top level Install
3873 * however for Administrative and uninstalls this step will be needed
3875 if (!package->PackagePath)
3876 return ERROR_SUCCESS;
3878 msi_set_sourcedir_props(package);
3880 attrib = GetFileAttributesW(package->PackagePath);
3881 if (attrib == INVALID_FILE_ATTRIBUTES)
3883 LPWSTR prompt;
3884 LPWSTR msg;
3885 DWORD size = 0;
3887 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3888 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3889 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3890 if (rc == ERROR_MORE_DATA)
3892 prompt = msi_alloc(size * sizeof(WCHAR));
3893 MsiSourceListGetInfoW(package->ProductCode, NULL,
3894 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3895 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3897 else
3898 prompt = strdupW(package->PackagePath);
3900 msg = generate_error_string(package,1302,1,prompt);
3901 while(attrib == INVALID_FILE_ATTRIBUTES)
3903 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3904 if (rc == IDCANCEL)
3906 rc = ERROR_INSTALL_USEREXIT;
3907 break;
3909 attrib = GetFileAttributesW(package->PackagePath);
3911 msi_free(prompt);
3912 rc = ERROR_SUCCESS;
3914 else
3915 return ERROR_SUCCESS;
3917 return rc;
3920 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3922 HKEY hkey=0;
3923 LPWSTR buffer;
3924 LPWSTR productid;
3925 UINT rc,i;
3927 static const WCHAR szPropKeys[][80] =
3929 {'P','r','o','d','u','c','t','I','D',0},
3930 {'U','S','E','R','N','A','M','E',0},
3931 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3932 {0},
3935 static const WCHAR szRegKeys[][80] =
3937 {'P','r','o','d','u','c','t','I','D',0},
3938 {'R','e','g','O','w','n','e','r',0},
3939 {'R','e','g','C','o','m','p','a','n','y',0},
3940 {0},
3943 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3944 if (!productid)
3945 return ERROR_SUCCESS;
3947 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3948 if (rc != ERROR_SUCCESS)
3949 goto end;
3951 for( i = 0; szPropKeys[i][0]; i++ )
3953 buffer = msi_dup_property( package, szPropKeys[i] );
3954 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3955 msi_free( buffer );
3958 end:
3959 msi_free(productid);
3960 RegCloseKey(hkey);
3962 /* FIXME: call ui_actiondata */
3964 return ERROR_SUCCESS;
3968 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3970 UINT rc;
3972 package->script->InWhatSequence |= SEQUENCE_EXEC;
3973 rc = ACTION_ProcessExecSequence(package,FALSE);
3974 return rc;
3978 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3980 MSIPACKAGE *package = (MSIPACKAGE*)param;
3981 LPCWSTR compgroupid=NULL;
3982 LPCWSTR feature=NULL;
3983 LPCWSTR text = NULL;
3984 LPCWSTR qualifier = NULL;
3985 LPCWSTR component = NULL;
3986 LPWSTR advertise = NULL;
3987 LPWSTR output = NULL;
3988 HKEY hkey;
3989 UINT rc = ERROR_SUCCESS;
3990 MSICOMPONENT *comp;
3991 DWORD sz = 0;
3992 MSIRECORD *uirow;
3994 component = MSI_RecordGetString(rec,3);
3995 comp = get_loaded_component(package,component);
3997 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3998 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3999 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4001 TRACE("Skipping: Component %s not scheduled for install\n",
4002 debugstr_w(component));
4004 return ERROR_SUCCESS;
4007 compgroupid = MSI_RecordGetString(rec,1);
4008 qualifier = MSI_RecordGetString(rec,2);
4010 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4011 if (rc != ERROR_SUCCESS)
4012 goto end;
4014 text = MSI_RecordGetString(rec,4);
4015 feature = MSI_RecordGetString(rec,5);
4017 advertise = create_component_advertise_string(package, comp, feature);
4019 sz = strlenW(advertise);
4021 if (text)
4022 sz += lstrlenW(text);
4024 sz+=3;
4025 sz *= sizeof(WCHAR);
4027 output = msi_alloc_zero(sz);
4028 strcpyW(output,advertise);
4029 msi_free(advertise);
4031 if (text)
4032 strcatW(output,text);
4034 msi_reg_set_val_multi_str( hkey, qualifier, output );
4036 end:
4037 RegCloseKey(hkey);
4038 msi_free(output);
4040 /* the UI chunk */
4041 uirow = MSI_CreateRecord( 2 );
4042 MSI_RecordSetStringW( uirow, 1, compgroupid );
4043 MSI_RecordSetStringW( uirow, 2, qualifier);
4044 ui_actiondata( package, szPublishComponents, uirow);
4045 msiobj_release( &uirow->hdr );
4046 /* FIXME: call ui_progress? */
4048 return rc;
4052 * At present I am ignorning the advertised components part of this and only
4053 * focusing on the qualified component sets
4055 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4057 UINT rc;
4058 MSIQUERY * view;
4059 static const WCHAR ExecSeqQuery[] =
4060 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4061 '`','P','u','b','l','i','s','h',
4062 'C','o','m','p','o','n','e','n','t','`',0};
4064 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4065 if (rc != ERROR_SUCCESS)
4066 return ERROR_SUCCESS;
4068 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4069 msiobj_release(&view->hdr);
4071 return rc;
4074 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4076 MSIPACKAGE *package = (MSIPACKAGE*)param;
4077 MSIRECORD *row;
4078 MSIFILE *file;
4079 SC_HANDLE hscm, service = NULL;
4080 LPCWSTR name, disp, comp, depends, pass;
4081 LPCWSTR load_order, serv_name, key;
4082 DWORD serv_type, start_type;
4083 DWORD err_control;
4085 static const WCHAR query[] =
4086 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4087 '`','C','o','m','p','o','n','e','n','t','`',' ',
4088 'W','H','E','R','E',' ',
4089 '`','C','o','m','p','o','n','e','n','t','`',' ',
4090 '=','\'','%','s','\'',0};
4092 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4093 if (!hscm)
4095 ERR("Failed to open the SC Manager!\n");
4096 goto done;
4099 start_type = MSI_RecordGetInteger(rec, 5);
4100 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4101 goto done;
4103 depends = MSI_RecordGetString(rec, 8);
4104 if (depends && *depends)
4105 FIXME("Dependency list unhandled!\n");
4107 name = MSI_RecordGetString(rec, 2);
4108 disp = MSI_RecordGetString(rec, 3);
4109 serv_type = MSI_RecordGetInteger(rec, 4);
4110 err_control = MSI_RecordGetInteger(rec, 6);
4111 load_order = MSI_RecordGetString(rec, 7);
4112 serv_name = MSI_RecordGetString(rec, 9);
4113 pass = MSI_RecordGetString(rec, 10);
4114 comp = MSI_RecordGetString(rec, 12);
4116 /* fetch the service path */
4117 row = MSI_QueryGetRecord(package->db, query, comp);
4118 if (!row)
4120 ERR("Control query failed!\n");
4121 goto done;
4124 key = MSI_RecordGetString(row, 6);
4125 msiobj_release(&row->hdr);
4127 file = get_loaded_file(package, key);
4128 if (!file)
4130 ERR("Failed to load the service file\n");
4131 goto done;
4134 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4135 start_type, err_control, file->TargetPath,
4136 load_order, NULL, NULL, serv_name, pass);
4137 if (!service)
4139 if (GetLastError() != ERROR_SERVICE_EXISTS)
4140 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4143 done:
4144 CloseServiceHandle(service);
4145 CloseServiceHandle(hscm);
4147 return ERROR_SUCCESS;
4150 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4152 UINT rc;
4153 MSIQUERY * view;
4154 static const WCHAR ExecSeqQuery[] =
4155 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4156 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4158 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4159 if (rc != ERROR_SUCCESS)
4160 return ERROR_SUCCESS;
4162 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4163 msiobj_release(&view->hdr);
4165 return rc;
4168 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4169 LPCSTR action, LPCWSTR table )
4171 static const WCHAR query[] = {
4172 'S','E','L','E','C','T',' ','*',' ',
4173 'F','R','O','M',' ','`','%','s','`',0 };
4174 MSIQUERY *view = NULL;
4175 DWORD count = 0;
4176 UINT r;
4178 r = MSI_OpenQuery( package->db, &view, query, table );
4179 if (r == ERROR_SUCCESS)
4181 r = MSI_IterateRecords(view, &count, NULL, package);
4182 msiobj_release(&view->hdr);
4185 if (count)
4186 FIXME("%s -> %u ignored %s table values\n",
4187 action, count, debugstr_w(table));
4189 return ERROR_SUCCESS;
4192 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4194 TRACE("%p\n", package);
4195 return ERROR_SUCCESS;
4198 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4200 static const WCHAR table[] =
4201 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4202 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4205 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4207 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4208 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4211 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4213 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4214 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4217 static UINT ACTION_BindImage( MSIPACKAGE *package )
4219 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4220 return msi_unimplemented_action_stub( package, "BindImage", table );
4223 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4225 static const WCHAR table[] = {
4226 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4227 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4230 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4232 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4233 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4236 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4238 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4239 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4242 static UINT ACTION_StartServices( MSIPACKAGE *package )
4244 static const WCHAR table[] = {
4245 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4246 return msi_unimplemented_action_stub( package, "StartServices", table );
4249 static UINT ACTION_StopServices( MSIPACKAGE *package )
4251 static const WCHAR table[] = {
4252 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4253 return msi_unimplemented_action_stub( package, "StopServices", table );
4256 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4258 static const WCHAR table[] = {
4259 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4260 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4263 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4265 static const WCHAR table[] = {
4266 'E','n','v','i','r','o','n','m','e','n','t',0 };
4267 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4270 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4272 static const WCHAR table[] = {
4273 'E','n','v','i','r','o','n','m','e','n','t',0 };
4274 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4277 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4279 static const WCHAR table[] = {
4280 'M','s','i','A','s','s','e','m','b','l','y',0 };
4281 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4284 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4286 static const WCHAR table[] = {
4287 'M','s','i','A','s','s','e','m','b','l','y',0 };
4288 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4291 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4293 static const WCHAR table[] = { 'F','o','n','t',0 };
4294 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4297 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4299 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4300 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4303 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4305 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4306 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4309 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4311 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4312 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4315 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4317 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4318 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4321 static struct _actions StandardActions[] = {
4322 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4323 { szAppSearch, ACTION_AppSearch },
4324 { szBindImage, ACTION_BindImage },
4325 { szCCPSearch, ACTION_CCPSearch},
4326 { szCostFinalize, ACTION_CostFinalize },
4327 { szCostInitialize, ACTION_CostInitialize },
4328 { szCreateFolders, ACTION_CreateFolders },
4329 { szCreateShortcuts, ACTION_CreateShortcuts },
4330 { szDeleteServices, ACTION_DeleteServices },
4331 { szDisableRollback, NULL},
4332 { szDuplicateFiles, ACTION_DuplicateFiles },
4333 { szExecuteAction, ACTION_ExecuteAction },
4334 { szFileCost, ACTION_FileCost },
4335 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4336 { szForceReboot, ACTION_ForceReboot },
4337 { szInstallAdminPackage, NULL},
4338 { szInstallExecute, ACTION_InstallExecute },
4339 { szInstallExecuteAgain, ACTION_InstallExecute },
4340 { szInstallFiles, ACTION_InstallFiles},
4341 { szInstallFinalize, ACTION_InstallFinalize },
4342 { szInstallInitialize, ACTION_InstallInitialize },
4343 { szInstallSFPCatalogFile, NULL},
4344 { szInstallValidate, ACTION_InstallValidate },
4345 { szIsolateComponents, ACTION_IsolateComponents },
4346 { szLaunchConditions, ACTION_LaunchConditions },
4347 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4348 { szMoveFiles, ACTION_MoveFiles },
4349 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4350 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4351 { szInstallODBC, NULL},
4352 { szInstallServices, ACTION_InstallServices },
4353 { szPatchFiles, ACTION_PatchFiles },
4354 { szProcessComponents, ACTION_ProcessComponents },
4355 { szPublishComponents, ACTION_PublishComponents },
4356 { szPublishFeatures, ACTION_PublishFeatures },
4357 { szPublishProduct, ACTION_PublishProduct },
4358 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4359 { szRegisterComPlus, ACTION_RegisterComPlus},
4360 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4361 { szRegisterFonts, ACTION_RegisterFonts },
4362 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4363 { szRegisterProduct, ACTION_RegisterProduct },
4364 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4365 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4366 { szRegisterUser, ACTION_RegisterUser},
4367 { szRemoveDuplicateFiles, NULL},
4368 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4369 { szRemoveExistingProducts, NULL},
4370 { szRemoveFiles, ACTION_RemoveFiles},
4371 { szRemoveFolders, NULL},
4372 { szRemoveIniValues, ACTION_RemoveIniValues },
4373 { szRemoveODBC, NULL},
4374 { szRemoveRegistryValues, NULL},
4375 { szRemoveShortcuts, NULL},
4376 { szResolveSource, ACTION_ResolveSource},
4377 { szRMCCPSearch, ACTION_RMCCPSearch},
4378 { szScheduleReboot, NULL},
4379 { szSelfRegModules, ACTION_SelfRegModules },
4380 { szSelfUnregModules, ACTION_SelfUnregModules },
4381 { szSetODBCFolders, NULL},
4382 { szStartServices, ACTION_StartServices },
4383 { szStopServices, ACTION_StopServices },
4384 { szUnpublishComponents, NULL},
4385 { szUnpublishFeatures, NULL},
4386 { szUnregisterClassInfo, NULL},
4387 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4388 { szUnregisterExtensionInfo, NULL},
4389 { szUnregisterFonts, ACTION_UnregisterFonts },
4390 { szUnregisterMIMEInfo, NULL},
4391 { szUnregisterProgIdInfo, NULL},
4392 { szUnregisterTypeLibraries, NULL},
4393 { szValidateProductID, NULL},
4394 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4395 { szWriteIniValues, ACTION_WriteIniValues },
4396 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4397 { NULL, NULL},