user32: ToUnicodeEx should return 0 for an unknown key.
[wine/dibdrv.git] / dlls / msi / action.c
blob8e7641398d9be5ea4892d2e984c884caf52133fb
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);
628 check = msi_dup_property( package, cszSOURCEDIR );
629 if (!check)
630 MSI_SetPropertyW(package, cszSOURCEDIR, path);
632 msi_free( package->PackagePath );
633 package->PackagePath = path;
635 msi_free(check);
638 msi_parse_command_line( package, szCommandLine );
640 msi_apply_transforms( package );
641 msi_apply_patches( package );
643 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
645 package->script->InWhatSequence |= SEQUENCE_UI;
646 rc = ACTION_ProcessUISequence(package);
647 ui = TRUE;
648 if (rc == ERROR_SUCCESS)
650 package->script->InWhatSequence |= SEQUENCE_EXEC;
651 rc = ACTION_ProcessExecSequence(package,TRUE);
654 else
655 rc = ACTION_ProcessExecSequence(package,FALSE);
657 if (rc == -1)
659 /* install was halted but should be considered a success */
660 rc = ERROR_SUCCESS;
663 package->script->CurrentlyScripting= FALSE;
665 /* process the ending type action */
666 if (rc == ERROR_SUCCESS)
667 ACTION_PerformActionSequence(package,-1,ui);
668 else if (rc == ERROR_INSTALL_USEREXIT)
669 ACTION_PerformActionSequence(package,-2,ui);
670 else if (rc == ERROR_INSTALL_SUSPEND)
671 ACTION_PerformActionSequence(package,-4,ui);
672 else /* failed */
673 ACTION_PerformActionSequence(package,-3,ui);
675 /* finish up running custom actions */
676 ACTION_FinishCustomActions(package);
678 return rc;
681 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
683 UINT rc = ERROR_SUCCESS;
684 MSIRECORD * row = 0;
685 static const WCHAR ExecSeqQuery[] =
686 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
687 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
688 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
689 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
691 static const WCHAR UISeqQuery[] =
692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
693 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
694 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
695 ' ', '=',' ','%','i',0};
697 if (UI)
698 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
699 else
700 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
702 if (row)
704 LPCWSTR action, cond;
706 TRACE("Running the actions\n");
708 /* check conditions */
709 cond = MSI_RecordGetString(row,2);
711 /* this is a hack to skip errors in the condition code */
712 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
713 goto end;
715 action = MSI_RecordGetString(row,1);
716 if (!action)
718 ERR("failed to fetch action\n");
719 rc = ERROR_FUNCTION_FAILED;
720 goto end;
723 if (UI)
724 rc = ACTION_PerformUIAction(package,action);
725 else
726 rc = ACTION_PerformAction(package,action,FALSE);
727 end:
728 msiobj_release(&row->hdr);
730 else
731 rc = ERROR_SUCCESS;
733 return rc;
736 typedef struct {
737 MSIPACKAGE* package;
738 BOOL UI;
739 } iterate_action_param;
741 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
743 iterate_action_param *iap= (iterate_action_param*)param;
744 UINT rc;
745 LPCWSTR cond, action;
747 action = MSI_RecordGetString(row,1);
748 if (!action)
750 ERR("Error is retrieving action name\n");
751 return ERROR_FUNCTION_FAILED;
754 /* check conditions */
755 cond = MSI_RecordGetString(row,2);
757 /* this is a hack to skip errors in the condition code */
758 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
760 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
761 return ERROR_SUCCESS;
764 if (iap->UI)
765 rc = ACTION_PerformUIAction(iap->package,action);
766 else
767 rc = ACTION_PerformAction(iap->package,action,FALSE);
769 msi_dialog_check_messages( NULL );
771 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
772 rc = iap->package->CurrentInstallState;
774 if (rc == ERROR_FUNCTION_NOT_CALLED)
775 rc = ERROR_SUCCESS;
777 if (rc != ERROR_SUCCESS)
778 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
780 return rc;
783 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
785 MSIQUERY * view;
786 UINT r;
787 static const WCHAR query[] =
788 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
789 '`','%','s','`',
790 ' ','W','H','E','R','E',' ',
791 '`','S','e','q','u','e','n','c','e','`',' ',
792 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
793 '`','S','e','q','u','e','n','c','e','`',0};
794 iterate_action_param iap;
797 * FIXME: probably should be checking UILevel in the
798 * ACTION_PerformUIAction/ACTION_PerformAction
799 * rather than saving the UI level here. Those
800 * two functions can be merged too.
802 iap.package = package;
803 iap.UI = TRUE;
805 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
807 r = MSI_OpenQuery( package->db, &view, query, szTable );
808 if (r == ERROR_SUCCESS)
810 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
811 msiobj_release(&view->hdr);
814 return r;
817 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
819 MSIQUERY * view;
820 UINT rc;
821 static const WCHAR ExecSeqQuery[] =
822 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
823 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
824 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
825 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
826 'O','R','D','E','R',' ', 'B','Y',' ',
827 '`','S','e','q','u','e','n','c','e','`',0 };
828 MSIRECORD * row = 0;
829 static const WCHAR IVQuery[] =
830 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
831 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
832 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
833 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
834 ' ','\'', 'I','n','s','t','a','l','l',
835 'V','a','l','i','d','a','t','e','\'', 0};
836 INT seq = 0;
837 iterate_action_param iap;
839 iap.package = package;
840 iap.UI = FALSE;
842 if (package->script->ExecuteSequenceRun)
844 TRACE("Execute Sequence already Run\n");
845 return ERROR_SUCCESS;
848 package->script->ExecuteSequenceRun = TRUE;
850 /* get the sequence number */
851 if (UIran)
853 row = MSI_QueryGetRecord(package->db, IVQuery);
854 if( !row )
855 return ERROR_FUNCTION_FAILED;
856 seq = MSI_RecordGetInteger(row,1);
857 msiobj_release(&row->hdr);
860 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
861 if (rc == ERROR_SUCCESS)
863 TRACE("Running the actions\n");
865 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
866 msiobj_release(&view->hdr);
869 return rc;
872 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
874 MSIQUERY * view;
875 UINT rc;
876 static const WCHAR ExecSeqQuery [] =
877 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
878 '`','I','n','s','t','a','l','l',
879 'U','I','S','e','q','u','e','n','c','e','`',
880 ' ','W','H','E','R','E',' ',
881 '`','S','e','q','u','e','n','c','e','`',' ',
882 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
883 '`','S','e','q','u','e','n','c','e','`',0};
884 iterate_action_param iap;
886 iap.package = package;
887 iap.UI = TRUE;
889 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
891 if (rc == ERROR_SUCCESS)
893 TRACE("Running the actions\n");
895 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
896 msiobj_release(&view->hdr);
899 return rc;
902 /********************************************************
903 * ACTION helper functions and functions that perform the actions
904 *******************************************************/
905 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
906 UINT* rc, BOOL force )
908 BOOL ret = FALSE;
909 BOOL run = force;
910 int i;
912 if (!run && !package->script->CurrentlyScripting)
913 run = TRUE;
915 if (!run)
917 if (strcmpW(action,szInstallFinalize) == 0 ||
918 strcmpW(action,szInstallExecute) == 0 ||
919 strcmpW(action,szInstallExecuteAgain) == 0)
920 run = TRUE;
923 i = 0;
924 while (StandardActions[i].action != NULL)
926 if (strcmpW(StandardActions[i].action, action)==0)
928 if (!run)
930 ui_actioninfo(package, action, TRUE, 0);
931 *rc = schedule_action(package,INSTALL_SCRIPT,action);
932 ui_actioninfo(package, action, FALSE, *rc);
934 else
936 ui_actionstart(package, action);
937 if (StandardActions[i].handler)
939 *rc = StandardActions[i].handler(package);
941 else
943 FIXME("unhandled standard action %s\n",debugstr_w(action));
944 *rc = ERROR_SUCCESS;
947 ret = TRUE;
948 break;
950 i++;
952 return ret;
955 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
956 UINT* rc, BOOL force )
958 BOOL ret=FALSE;
959 UINT arc;
961 arc = ACTION_CustomAction(package,action, force);
963 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
965 *rc = arc;
966 ret = TRUE;
968 return ret;
972 * A lot of actions are really important even if they don't do anything
973 * explicit... Lots of properties are set at the beginning of the installation
974 * CostFinalize does a bunch of work to translate the directories and such
976 * But until I get write access to the database that is hard, so I am going to
977 * hack it to see if I can get something to run.
979 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
981 UINT rc = ERROR_SUCCESS;
982 BOOL handled;
984 TRACE("Performing action (%s)\n",debugstr_w(action));
986 handled = ACTION_HandleStandardAction(package, action, &rc, force);
988 if (!handled)
989 handled = ACTION_HandleCustomAction(package, action, &rc, force);
991 if (!handled)
993 FIXME("unhandled msi action %s\n",debugstr_w(action));
994 rc = ERROR_FUNCTION_NOT_CALLED;
997 return rc;
1000 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1002 UINT rc = ERROR_SUCCESS;
1003 BOOL handled = FALSE;
1005 TRACE("Performing action (%s)\n",debugstr_w(action));
1007 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1009 if (!handled)
1010 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1012 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1013 handled = TRUE;
1015 if (!handled)
1017 FIXME("unhandled msi action %s\n",debugstr_w(action));
1018 rc = ERROR_FUNCTION_NOT_CALLED;
1021 return rc;
1026 * Actual Action Handlers
1029 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1031 MSIPACKAGE *package = (MSIPACKAGE*)param;
1032 LPCWSTR dir;
1033 LPWSTR full_path;
1034 MSIRECORD *uirow;
1035 MSIFOLDER *folder;
1037 dir = MSI_RecordGetString(row,1);
1038 if (!dir)
1040 ERR("Unable to get folder id\n");
1041 return ERROR_SUCCESS;
1044 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1045 if (!full_path)
1047 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1048 return ERROR_SUCCESS;
1051 TRACE("Folder is %s\n",debugstr_w(full_path));
1053 /* UI stuff */
1054 uirow = MSI_CreateRecord(1);
1055 MSI_RecordSetStringW(uirow,1,full_path);
1056 ui_actiondata(package,szCreateFolders,uirow);
1057 msiobj_release( &uirow->hdr );
1059 if (folder->State == 0)
1060 create_full_pathW(full_path);
1062 folder->State = 3;
1064 msi_free(full_path);
1065 return ERROR_SUCCESS;
1068 /* FIXME: probably should merge this with the above function */
1069 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1071 UINT rc = ERROR_SUCCESS;
1072 MSIFOLDER *folder;
1073 LPWSTR install_path;
1075 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1076 if (!install_path)
1077 return ERROR_FUNCTION_FAILED;
1079 /* create the path */
1080 if (folder->State == 0)
1082 create_full_pathW(install_path);
1083 folder->State = 2;
1085 msi_free(install_path);
1087 return rc;
1090 UINT msi_create_component_directories( MSIPACKAGE *package )
1092 MSICOMPONENT *comp;
1094 /* create all the folders required by the components are going to install */
1095 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1097 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1098 continue;
1099 msi_create_directory( package, comp->Directory );
1102 return ERROR_SUCCESS;
1106 * Also we cannot enable/disable components either, so for now I am just going
1107 * to do all the directories for all the components.
1109 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1111 static const WCHAR ExecSeqQuery[] =
1112 {'S','E','L','E','C','T',' ',
1113 '`','D','i','r','e','c','t','o','r','y','_','`',
1114 ' ','F','R','O','M',' ',
1115 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1116 UINT rc;
1117 MSIQUERY *view;
1119 /* create all the empty folders specified in the CreateFolder table */
1120 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1121 if (rc != ERROR_SUCCESS)
1122 return ERROR_SUCCESS;
1124 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1125 msiobj_release(&view->hdr);
1127 msi_create_component_directories( package );
1129 return rc;
1132 static UINT load_component( MSIRECORD *row, LPVOID param )
1134 MSIPACKAGE *package = param;
1135 MSICOMPONENT *comp;
1137 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1138 if (!comp)
1139 return ERROR_FUNCTION_FAILED;
1141 list_add_tail( &package->components, &comp->entry );
1143 /* fill in the data */
1144 comp->Component = msi_dup_record_field( row, 1 );
1146 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1148 comp->ComponentId = msi_dup_record_field( row, 2 );
1149 comp->Directory = msi_dup_record_field( row, 3 );
1150 comp->Attributes = MSI_RecordGetInteger(row,4);
1151 comp->Condition = msi_dup_record_field( row, 5 );
1152 comp->KeyPath = msi_dup_record_field( row, 6 );
1154 comp->Installed = INSTALLSTATE_UNKNOWN;
1155 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1157 return ERROR_SUCCESS;
1160 static UINT load_all_components( MSIPACKAGE *package )
1162 static const WCHAR query[] = {
1163 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1164 '`','C','o','m','p','o','n','e','n','t','`',0 };
1165 MSIQUERY *view;
1166 UINT r;
1168 if (!list_empty(&package->components))
1169 return ERROR_SUCCESS;
1171 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1172 if (r != ERROR_SUCCESS)
1173 return r;
1175 r = MSI_IterateRecords(view, NULL, load_component, package);
1176 msiobj_release(&view->hdr);
1177 return r;
1180 typedef struct {
1181 MSIPACKAGE *package;
1182 MSIFEATURE *feature;
1183 } _ilfs;
1185 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1187 ComponentList *cl;
1189 cl = msi_alloc( sizeof (*cl) );
1190 if ( !cl )
1191 return ERROR_NOT_ENOUGH_MEMORY;
1192 cl->component = comp;
1193 list_add_tail( &feature->Components, &cl->entry );
1195 return ERROR_SUCCESS;
1198 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1200 FeatureList *fl;
1202 fl = msi_alloc( sizeof(*fl) );
1203 if ( !fl )
1204 return ERROR_NOT_ENOUGH_MEMORY;
1205 fl->feature = child;
1206 list_add_tail( &parent->Children, &fl->entry );
1208 return ERROR_SUCCESS;
1211 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1213 _ilfs* ilfs= (_ilfs*)param;
1214 LPCWSTR component;
1215 MSICOMPONENT *comp;
1217 component = MSI_RecordGetString(row,1);
1219 /* check to see if the component is already loaded */
1220 comp = get_loaded_component( ilfs->package, component );
1221 if (!comp)
1223 ERR("unknown component %s\n", debugstr_w(component));
1224 return ERROR_FUNCTION_FAILED;
1227 add_feature_component( ilfs->feature, comp );
1228 comp->Enabled = TRUE;
1230 return ERROR_SUCCESS;
1233 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1235 MSIFEATURE *feature;
1237 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1239 if ( !lstrcmpW( feature->Feature, name ) )
1240 return feature;
1243 return NULL;
1246 static UINT load_feature(MSIRECORD * row, LPVOID param)
1248 MSIPACKAGE* package = (MSIPACKAGE*)param;
1249 MSIFEATURE* feature;
1250 static const WCHAR Query1[] =
1251 {'S','E','L','E','C','T',' ',
1252 '`','C','o','m','p','o','n','e','n','t','_','`',
1253 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1254 'C','o','m','p','o','n','e','n','t','s','`',' ',
1255 'W','H','E','R','E',' ',
1256 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1257 MSIQUERY * view;
1258 UINT rc;
1259 _ilfs ilfs;
1261 /* fill in the data */
1263 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1264 if (!feature)
1265 return ERROR_NOT_ENOUGH_MEMORY;
1267 list_init( &feature->Children );
1268 list_init( &feature->Components );
1270 feature->Feature = msi_dup_record_field( row, 1 );
1272 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1274 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1275 feature->Title = msi_dup_record_field( row, 3 );
1276 feature->Description = msi_dup_record_field( row, 4 );
1278 if (!MSI_RecordIsNull(row,5))
1279 feature->Display = MSI_RecordGetInteger(row,5);
1281 feature->Level= MSI_RecordGetInteger(row,6);
1282 feature->Directory = msi_dup_record_field( row, 7 );
1283 feature->Attributes = MSI_RecordGetInteger(row,8);
1285 feature->Installed = INSTALLSTATE_UNKNOWN;
1286 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1288 list_add_tail( &package->features, &feature->entry );
1290 /* load feature components */
1292 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1293 if (rc != ERROR_SUCCESS)
1294 return ERROR_SUCCESS;
1296 ilfs.package = package;
1297 ilfs.feature = feature;
1299 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1300 msiobj_release(&view->hdr);
1302 return ERROR_SUCCESS;
1305 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1307 MSIPACKAGE* package = (MSIPACKAGE*)param;
1308 MSIFEATURE *parent, *child;
1310 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1311 if (!child)
1312 return ERROR_FUNCTION_FAILED;
1314 if (!child->Feature_Parent)
1315 return ERROR_SUCCESS;
1317 parent = find_feature_by_name( package, child->Feature_Parent );
1318 if (!parent)
1319 return ERROR_FUNCTION_FAILED;
1321 add_feature_child( parent, child );
1322 return ERROR_SUCCESS;
1325 static UINT load_all_features( MSIPACKAGE *package )
1327 static const WCHAR query[] = {
1328 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1329 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1330 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1331 MSIQUERY *view;
1332 UINT r;
1334 if (!list_empty(&package->features))
1335 return ERROR_SUCCESS;
1337 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1338 if (r != ERROR_SUCCESS)
1339 return r;
1341 r = MSI_IterateRecords( view, NULL, load_feature, package );
1342 if (r != ERROR_SUCCESS)
1343 return r;
1345 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1346 msiobj_release( &view->hdr );
1348 return r;
1351 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1353 if (!p)
1354 return p;
1355 p = strchrW(p, ch);
1356 if (!p)
1357 return p;
1358 *p = 0;
1359 return p+1;
1362 static UINT load_file(MSIRECORD *row, LPVOID param)
1364 MSIPACKAGE* package = (MSIPACKAGE*)param;
1365 LPCWSTR component;
1366 MSIFILE *file;
1368 /* fill in the data */
1370 file = msi_alloc_zero( sizeof (MSIFILE) );
1371 if (!file)
1372 return ERROR_NOT_ENOUGH_MEMORY;
1374 file->File = msi_dup_record_field( row, 1 );
1376 component = MSI_RecordGetString( row, 2 );
1377 file->Component = get_loaded_component( package, component );
1379 if (!file->Component)
1380 ERR("Unfound Component %s\n",debugstr_w(component));
1382 file->FileName = msi_dup_record_field( row, 3 );
1383 reduce_to_longfilename( file->FileName );
1385 file->ShortName = msi_dup_record_field( row, 3 );
1386 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1388 file->FileSize = MSI_RecordGetInteger( row, 4 );
1389 file->Version = msi_dup_record_field( row, 5 );
1390 file->Language = msi_dup_record_field( row, 6 );
1391 file->Attributes = MSI_RecordGetInteger( row, 7 );
1392 file->Sequence = MSI_RecordGetInteger( row, 8 );
1394 file->state = msifs_invalid;
1396 /* if the compressed bits are not set in the file attributes,
1397 * then read the information from the package word count property
1399 if (file->Attributes & msidbFileAttributesCompressed)
1401 file->IsCompressed = TRUE;
1403 else if (file->Attributes & msidbFileAttributesNoncompressed)
1405 file->IsCompressed = FALSE;
1407 else
1409 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1412 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1414 list_add_tail( &package->files, &file->entry );
1416 return ERROR_SUCCESS;
1419 static UINT load_all_files(MSIPACKAGE *package)
1421 MSIQUERY * view;
1422 UINT rc;
1423 static const WCHAR Query[] =
1424 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1425 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1426 '`','S','e','q','u','e','n','c','e','`', 0};
1428 if (!list_empty(&package->files))
1429 return ERROR_SUCCESS;
1431 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1432 if (rc != ERROR_SUCCESS)
1433 return ERROR_SUCCESS;
1435 rc = MSI_IterateRecords(view, NULL, load_file, package);
1436 msiobj_release(&view->hdr);
1438 return ERROR_SUCCESS;
1443 * I am not doing any of the costing functionality yet.
1444 * Mostly looking at doing the Component and Feature loading
1446 * The native MSI does A LOT of modification to tables here. Mostly adding
1447 * a lot of temporary columns to the Feature and Component tables.
1449 * note: Native msi also tracks the short filename. But I am only going to
1450 * track the long ones. Also looking at this directory table
1451 * it appears that the directory table does not get the parents
1452 * resolved base on property only based on their entries in the
1453 * directory table.
1455 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1457 static const WCHAR szCosting[] =
1458 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1459 static const WCHAR szZero[] = { '0', 0 };
1461 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1462 return ERROR_SUCCESS;
1464 MSI_SetPropertyW(package, szCosting, szZero);
1465 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1467 load_all_components( package );
1468 load_all_features( package );
1469 load_all_files( package );
1471 return ERROR_SUCCESS;
1474 static UINT execute_script(MSIPACKAGE *package, UINT script )
1476 int i;
1477 UINT rc = ERROR_SUCCESS;
1479 TRACE("Executing Script %i\n",script);
1481 if (!package->script)
1483 ERR("no script!\n");
1484 return ERROR_FUNCTION_FAILED;
1487 for (i = 0; i < package->script->ActionCount[script]; i++)
1489 LPWSTR action;
1490 action = package->script->Actions[script][i];
1491 ui_actionstart(package, action);
1492 TRACE("Executing Action (%s)\n",debugstr_w(action));
1493 rc = ACTION_PerformAction(package, action, TRUE);
1494 if (rc != ERROR_SUCCESS)
1495 break;
1497 msi_free_action_script(package, script);
1498 return rc;
1501 static UINT ACTION_FileCost(MSIPACKAGE *package)
1503 return ERROR_SUCCESS;
1506 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
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','`',' ',
1511 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1512 ' ','=',' ','\'','%','s','\'',
1514 static const WCHAR szDot[] = { '.',0 };
1515 static WCHAR szEmpty[] = { 0 };
1516 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1517 LPCWSTR parent;
1518 MSIRECORD *row;
1519 MSIFOLDER *folder;
1521 TRACE("Looking for dir %s\n",debugstr_w(dir));
1523 folder = get_loaded_folder( package, dir );
1524 if (folder)
1525 return folder;
1527 TRACE("Working to load %s\n",debugstr_w(dir));
1529 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1530 if (!folder)
1531 return NULL;
1533 folder->Directory = strdupW(dir);
1535 row = MSI_QueryGetRecord(package->db, Query, dir);
1536 if (!row)
1537 return NULL;
1539 p = msi_dup_record_field(row, 3);
1541 /* split src and target dir */
1542 tgt_short = p;
1543 src_short = folder_split_path( p, ':' );
1545 /* split the long and short paths */
1546 tgt_long = folder_split_path( tgt_short, '|' );
1547 src_long = folder_split_path( src_short, '|' );
1549 /* check for no-op dirs */
1550 if (!lstrcmpW(szDot, tgt_short))
1551 tgt_short = szEmpty;
1552 if (!lstrcmpW(szDot, src_short))
1553 src_short = szEmpty;
1555 if (!tgt_long)
1556 tgt_long = tgt_short;
1558 if (!src_short) {
1559 src_short = tgt_short;
1560 src_long = tgt_long;
1563 if (!src_long)
1564 src_long = src_short;
1566 /* FIXME: use the target short path too */
1567 folder->TargetDefault = strdupW(tgt_long);
1568 folder->SourceShortPath = strdupW(src_short);
1569 folder->SourceLongPath = strdupW(src_long);
1570 msi_free(p);
1572 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1573 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1574 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1576 parent = MSI_RecordGetString(row, 2);
1577 if (parent)
1579 folder->Parent = load_folder( package, parent );
1580 if ( folder->Parent )
1581 TRACE("loaded parent %p %s\n", folder->Parent,
1582 debugstr_w(folder->Parent->Directory));
1583 else
1584 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1587 folder->Property = msi_dup_property( package, dir );
1589 msiobj_release(&row->hdr);
1591 list_add_tail( &package->folders, &folder->entry );
1593 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1595 return folder;
1598 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1600 MSICOMPONENT *comp;
1602 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1604 INSTALLSTATE res;
1606 if (!comp->ComponentId)
1607 continue;
1609 res = MsiGetComponentPathW( package->ProductCode,
1610 comp->ComponentId, NULL, NULL);
1611 if (res < 0)
1612 res = INSTALLSTATE_ABSENT;
1613 comp->Installed = res;
1617 /* scan for and update current install states */
1618 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1620 MSICOMPONENT *comp;
1621 MSIFEATURE *feature;
1623 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1625 ComponentList *cl;
1626 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1628 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1630 comp= cl->component;
1632 if (!comp->ComponentId)
1634 res = INSTALLSTATE_ABSENT;
1635 break;
1638 if (res == INSTALLSTATE_ABSENT)
1639 res = comp->Installed;
1640 else
1642 if (res == comp->Installed)
1643 continue;
1645 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1646 res != INSTALLSTATE_SOURCE)
1648 res = INSTALLSTATE_INCOMPLETE;
1652 feature->Installed = res;
1656 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1657 INSTALLSTATE state)
1659 static const WCHAR all[]={'A','L','L',0};
1660 LPWSTR override;
1661 MSIFEATURE *feature;
1663 override = msi_dup_property( package, property );
1664 if (!override)
1665 return FALSE;
1667 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1669 if (strcmpiW(override,all)==0)
1670 msi_feature_set_state( feature, state );
1671 else
1673 LPWSTR ptr = override;
1674 LPWSTR ptr2 = strchrW(override,',');
1676 while (ptr)
1678 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1679 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1681 msi_feature_set_state( feature, state );
1682 break;
1684 if (ptr2)
1686 ptr=ptr2+1;
1687 ptr2 = strchrW(ptr,',');
1689 else
1690 break;
1694 msi_free(override);
1696 return TRUE;
1699 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1701 int install_level;
1702 static const WCHAR szlevel[] =
1703 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1704 static const WCHAR szAddLocal[] =
1705 {'A','D','D','L','O','C','A','L',0};
1706 static const WCHAR szRemove[] =
1707 {'R','E','M','O','V','E',0};
1708 static const WCHAR szReinstall[] =
1709 {'R','E','I','N','S','T','A','L','L',0};
1710 BOOL override = FALSE;
1711 MSICOMPONENT* component;
1712 MSIFEATURE *feature;
1715 /* I do not know if this is where it should happen.. but */
1717 TRACE("Checking Install Level\n");
1719 install_level = msi_get_property_int( package, szlevel, 1 );
1721 /* ok here is the _real_ rub
1722 * all these activation/deactivation things happen in order and things
1723 * later on the list override things earlier on the list.
1724 * 1) INSTALLLEVEL processing
1725 * 2) ADDLOCAL
1726 * 3) REMOVE
1727 * 4) ADDSOURCE
1728 * 5) ADDDEFAULT
1729 * 6) REINSTALL
1730 * 7) COMPADDLOCAL
1731 * 8) COMPADDSOURCE
1732 * 9) FILEADDLOCAL
1733 * 10) FILEADDSOURCE
1734 * 11) FILEADDDEFAULT
1735 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1736 * ignored for all the features. seems strange, especially since it is not
1737 * documented anywhere, but it is how it works.
1739 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1740 * REMOVE are the big ones, since we don't handle administrative installs
1741 * yet anyway.
1743 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1744 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1745 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1747 if (!override)
1749 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1751 BOOL feature_state = ((feature->Level > 0) &&
1752 (feature->Level <= install_level));
1754 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1756 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1757 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1758 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1759 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1760 else
1761 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1765 /* disable child features of unselected parent features */
1766 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1768 FeatureList *fl;
1770 if (feature->Level > 0 && feature->Level <= install_level)
1771 continue;
1773 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1774 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1777 else
1779 /* set the Preselected Property */
1780 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1781 static const WCHAR szOne[] = { '1', 0 };
1783 MSI_SetPropertyW(package,szPreselected,szOne);
1787 * now we want to enable or disable components base on feature
1790 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1792 ComponentList *cl;
1794 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1795 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1796 feature->ActionRequest);
1798 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1800 component = cl->component;
1802 switch (component->Attributes)
1804 case msidbComponentAttributesLocalOnly:
1805 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1806 break;
1807 case msidbComponentAttributesSourceOnly:
1808 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1809 break;
1810 case msidbComponentAttributesOptional:
1811 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1812 break;
1813 default:
1814 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1817 if (component->ForceLocalState)
1818 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1820 if (!component->Enabled)
1821 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1822 else if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1824 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1825 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1827 else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1829 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1830 (component->Action == INSTALLSTATE_ABSENT) ||
1831 (component->Action == INSTALLSTATE_ADVERTISED) ||
1832 (component->Action == INSTALLSTATE_DEFAULT))
1833 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1835 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1837 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1838 (component->Action == INSTALLSTATE_ABSENT))
1839 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1841 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1843 if (component->Action == INSTALLSTATE_UNKNOWN)
1844 msi_component_set_state( component, INSTALLSTATE_ABSENT );
1846 else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1847 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1849 if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1850 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1854 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1856 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1857 debugstr_w(component->Component), component->Installed,
1858 component->Action, component->ActionRequest);
1862 return ERROR_SUCCESS;
1865 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1867 MSIPACKAGE *package = (MSIPACKAGE*)param;
1868 LPCWSTR name;
1869 LPWSTR path;
1871 name = MSI_RecordGetString(row,1);
1873 /* This helper function now does ALL the work */
1874 TRACE("Dir %s ...\n",debugstr_w(name));
1875 load_folder(package,name);
1876 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1877 TRACE("resolves to %s\n",debugstr_w(path));
1878 msi_free(path);
1880 return ERROR_SUCCESS;
1883 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1885 MSIPACKAGE *package = (MSIPACKAGE*)param;
1886 LPCWSTR name;
1887 MSIFEATURE *feature;
1889 name = MSI_RecordGetString( row, 1 );
1891 feature = get_loaded_feature( package, name );
1892 if (!feature)
1893 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1894 else
1896 LPCWSTR Condition;
1897 Condition = MSI_RecordGetString(row,3);
1899 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1901 int level = MSI_RecordGetInteger(row,2);
1902 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1903 feature->Level = level;
1906 return ERROR_SUCCESS;
1909 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1911 static const WCHAR name_fmt[] =
1912 {'%','u','.','%','u','.','%','u','.','%','u',0};
1913 static WCHAR name[] = {'\\',0};
1914 VS_FIXEDFILEINFO *lpVer;
1915 WCHAR filever[0x100];
1916 LPVOID version;
1917 DWORD versize;
1918 DWORD handle;
1919 UINT sz;
1921 TRACE("%s\n", debugstr_w(filename));
1923 versize = GetFileVersionInfoSizeW( filename, &handle );
1924 if (!versize)
1925 return NULL;
1927 version = msi_alloc( versize );
1928 GetFileVersionInfoW( filename, 0, versize, version );
1930 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1931 msi_free( version );
1933 sprintfW( filever, name_fmt,
1934 HIWORD(lpVer->dwFileVersionMS),
1935 LOWORD(lpVer->dwFileVersionMS),
1936 HIWORD(lpVer->dwFileVersionLS),
1937 LOWORD(lpVer->dwFileVersionLS));
1939 return strdupW( filever );
1943 * A lot is done in this function aside from just the costing.
1944 * The costing needs to be implemented at some point but for now I am going
1945 * to focus on the directory building
1948 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1950 static const WCHAR ExecSeqQuery[] =
1951 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1952 '`','D','i','r','e','c','t','o','r','y','`',0};
1953 static const WCHAR ConditionQuery[] =
1954 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1955 '`','C','o','n','d','i','t','i','o','n','`',0};
1956 static const WCHAR szCosting[] =
1957 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1958 static const WCHAR szlevel[] =
1959 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1960 static const WCHAR szOne[] = { '1', 0 };
1961 MSICOMPONENT *comp;
1962 MSIFILE *file;
1963 UINT rc;
1964 MSIQUERY * view;
1965 LPWSTR level, file_version;
1967 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1968 return ERROR_SUCCESS;
1970 TRACE("Building Directory properties\n");
1972 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1973 if (rc == ERROR_SUCCESS)
1975 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1976 package);
1977 msiobj_release(&view->hdr);
1980 /* read components states from the registry */
1981 ACTION_GetComponentInstallStates(package);
1983 TRACE("File calculations\n");
1985 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1987 MSICOMPONENT* comp = file->Component;
1988 LPWSTR p;
1990 if (!comp)
1991 continue;
1993 if (file->IsCompressed)
1994 comp->ForceLocalState = TRUE;
1996 /* calculate target */
1997 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1999 msi_free(file->TargetPath);
2001 TRACE("file %s is named %s\n",
2002 debugstr_w(file->File), debugstr_w(file->FileName));
2004 file->TargetPath = build_directory_name(2, p, file->FileName);
2006 msi_free(p);
2008 TRACE("file %s resolves to %s\n",
2009 debugstr_w(file->File), debugstr_w(file->TargetPath));
2011 /* don't check files of components that aren't installed */
2012 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2013 comp->Installed == INSTALLSTATE_ABSENT)
2015 file->state = msifs_missing; /* assume files are missing */
2016 continue;
2019 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2021 file->state = msifs_missing;
2022 comp->Cost += file->FileSize;
2023 comp->Installed = INSTALLSTATE_INCOMPLETE;
2024 continue;
2027 if (file->Version &&
2028 (file_version = msi_get_disk_file_version( file->TargetPath )))
2030 TRACE("new %s old %s\n", debugstr_w(file->Version),
2031 debugstr_w(file_version));
2032 /* FIXME: seems like a bad way to compare version numbers */
2033 if (lstrcmpiW(file_version, file->Version)<0)
2035 file->state = msifs_overwrite;
2036 comp->Cost += file->FileSize;
2037 comp->Installed = INSTALLSTATE_INCOMPLETE;
2039 else
2040 file->state = msifs_present;
2041 msi_free( file_version );
2043 else
2044 file->state = msifs_present;
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 scheduleing */
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 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3847 DWORD attrib, len;
3848 LPWSTR ptr, source;
3849 UINT rc;
3852 * we are currently doing what should be done here in the top level Install
3853 * however for Adminastrative and uninstalls this step will be needed
3855 if (!package->PackagePath)
3856 return ERROR_SUCCESS;
3858 ptr = strrchrW(package->PackagePath, '\\');
3859 if (!ptr)
3860 return ERROR_SUCCESS;
3862 len = ptr - package->PackagePath + 2;
3863 source = msi_alloc(len * sizeof(WCHAR));
3864 lstrcpynW(source, package->PackagePath, len);
3866 MSI_SetPropertyW(package, cszSourceDir, source);
3867 MSI_SetPropertyW(package, cszSOURCEDIR, source);
3869 msi_free(source);
3871 attrib = GetFileAttributesW(package->PackagePath);
3872 if (attrib == INVALID_FILE_ATTRIBUTES)
3874 LPWSTR prompt;
3875 LPWSTR msg;
3876 DWORD size = 0;
3878 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3879 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3880 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3881 if (rc == ERROR_MORE_DATA)
3883 prompt = msi_alloc(size * sizeof(WCHAR));
3884 MsiSourceListGetInfoW(package->ProductCode, NULL,
3885 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3886 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3888 else
3889 prompt = strdupW(package->PackagePath);
3891 msg = generate_error_string(package,1302,1,prompt);
3892 while(attrib == INVALID_FILE_ATTRIBUTES)
3894 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3895 if (rc == IDCANCEL)
3897 rc = ERROR_INSTALL_USEREXIT;
3898 break;
3900 attrib = GetFileAttributesW(package->PackagePath);
3902 msi_free(prompt);
3903 rc = ERROR_SUCCESS;
3905 else
3906 return ERROR_SUCCESS;
3908 return rc;
3911 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3913 HKEY hkey=0;
3914 LPWSTR buffer;
3915 LPWSTR productid;
3916 UINT rc,i;
3918 static const WCHAR szPropKeys[][80] =
3920 {'P','r','o','d','u','c','t','I','D',0},
3921 {'U','S','E','R','N','A','M','E',0},
3922 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3923 {0},
3926 static const WCHAR szRegKeys[][80] =
3928 {'P','r','o','d','u','c','t','I','D',0},
3929 {'R','e','g','O','w','n','e','r',0},
3930 {'R','e','g','C','o','m','p','a','n','y',0},
3931 {0},
3934 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3935 if (!productid)
3936 return ERROR_SUCCESS;
3938 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3939 if (rc != ERROR_SUCCESS)
3940 goto end;
3942 for( i = 0; szPropKeys[i][0]; i++ )
3944 buffer = msi_dup_property( package, szPropKeys[i] );
3945 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3946 msi_free( buffer );
3949 end:
3950 msi_free(productid);
3951 RegCloseKey(hkey);
3953 /* FIXME: call ui_actiondata */
3955 return ERROR_SUCCESS;
3959 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3961 UINT rc;
3963 package->script->InWhatSequence |= SEQUENCE_EXEC;
3964 rc = ACTION_ProcessExecSequence(package,FALSE);
3965 return rc;
3969 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3971 MSIPACKAGE *package = (MSIPACKAGE*)param;
3972 LPCWSTR compgroupid=NULL;
3973 LPCWSTR feature=NULL;
3974 LPCWSTR text = NULL;
3975 LPCWSTR qualifier = NULL;
3976 LPCWSTR component = NULL;
3977 LPWSTR advertise = NULL;
3978 LPWSTR output = NULL;
3979 HKEY hkey;
3980 UINT rc = ERROR_SUCCESS;
3981 MSICOMPONENT *comp;
3982 DWORD sz = 0;
3983 MSIRECORD *uirow;
3985 component = MSI_RecordGetString(rec,3);
3986 comp = get_loaded_component(package,component);
3988 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
3989 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3990 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3992 TRACE("Skipping: Component %s not scheduled for install\n",
3993 debugstr_w(component));
3995 return ERROR_SUCCESS;
3998 compgroupid = MSI_RecordGetString(rec,1);
3999 qualifier = MSI_RecordGetString(rec,2);
4001 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4002 if (rc != ERROR_SUCCESS)
4003 goto end;
4005 text = MSI_RecordGetString(rec,4);
4006 feature = MSI_RecordGetString(rec,5);
4008 advertise = create_component_advertise_string(package, comp, feature);
4010 sz = strlenW(advertise);
4012 if (text)
4013 sz += lstrlenW(text);
4015 sz+=3;
4016 sz *= sizeof(WCHAR);
4018 output = msi_alloc_zero(sz);
4019 strcpyW(output,advertise);
4020 msi_free(advertise);
4022 if (text)
4023 strcatW(output,text);
4025 msi_reg_set_val_multi_str( hkey, qualifier, output );
4027 end:
4028 RegCloseKey(hkey);
4029 msi_free(output);
4031 /* the UI chunk */
4032 uirow = MSI_CreateRecord( 2 );
4033 MSI_RecordSetStringW( uirow, 1, compgroupid );
4034 MSI_RecordSetStringW( uirow, 2, qualifier);
4035 ui_actiondata( package, szPublishComponents, uirow);
4036 msiobj_release( &uirow->hdr );
4037 /* FIXME: call ui_progress? */
4039 return rc;
4043 * At present I am ignorning the advertised components part of this and only
4044 * focusing on the qualified component sets
4046 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4048 UINT rc;
4049 MSIQUERY * view;
4050 static const WCHAR ExecSeqQuery[] =
4051 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4052 '`','P','u','b','l','i','s','h',
4053 'C','o','m','p','o','n','e','n','t','`',0};
4055 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4056 if (rc != ERROR_SUCCESS)
4057 return ERROR_SUCCESS;
4059 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4060 msiobj_release(&view->hdr);
4062 return rc;
4065 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4067 MSIPACKAGE *package = (MSIPACKAGE*)param;
4068 MSIRECORD *row;
4069 MSIFILE *file;
4070 SC_HANDLE hscm, service = NULL;
4071 LPCWSTR name, disp, comp, depends, pass;
4072 LPCWSTR load_order, serv_name, key;
4073 DWORD serv_type, start_type;
4074 DWORD err_control;
4076 static const WCHAR query[] =
4077 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4078 '`','C','o','m','p','o','n','e','n','t','`',' ',
4079 'W','H','E','R','E',' ',
4080 '`','C','o','m','p','o','n','e','n','t','`',' ',
4081 '=','\'','%','s','\'',0};
4083 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4084 if (!hscm)
4086 ERR("Failed to open the SC Manager!\n");
4087 goto done;
4090 start_type = MSI_RecordGetInteger(rec, 5);
4091 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4092 goto done;
4094 depends = MSI_RecordGetString(rec, 8);
4095 if (depends && *depends)
4096 FIXME("Dependency list unhandled!\n");
4098 name = MSI_RecordGetString(rec, 2);
4099 disp = MSI_RecordGetString(rec, 3);
4100 serv_type = MSI_RecordGetInteger(rec, 4);
4101 err_control = MSI_RecordGetInteger(rec, 6);
4102 load_order = MSI_RecordGetString(rec, 7);
4103 serv_name = MSI_RecordGetString(rec, 9);
4104 pass = MSI_RecordGetString(rec, 10);
4105 comp = MSI_RecordGetString(rec, 12);
4107 /* fetch the service path */
4108 row = MSI_QueryGetRecord(package->db, query, comp);
4109 if (!row)
4111 ERR("Control query failed!\n");
4112 goto done;
4115 key = MSI_RecordGetString(row, 6);
4116 msiobj_release(&row->hdr);
4118 file = get_loaded_file(package, key);
4119 if (!file)
4121 ERR("Failed to load the service file\n");
4122 goto done;
4125 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4126 start_type, err_control, file->TargetPath,
4127 load_order, NULL, NULL, serv_name, pass);
4128 if (!service)
4130 if (GetLastError() != ERROR_SERVICE_EXISTS)
4131 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4134 done:
4135 CloseServiceHandle(service);
4136 CloseServiceHandle(hscm);
4138 return ERROR_SUCCESS;
4141 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4143 UINT rc;
4144 MSIQUERY * view;
4145 static const WCHAR ExecSeqQuery[] =
4146 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4147 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4149 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4150 if (rc != ERROR_SUCCESS)
4151 return ERROR_SUCCESS;
4153 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4154 msiobj_release(&view->hdr);
4156 return rc;
4159 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4160 LPCSTR action, LPCWSTR table )
4162 static const WCHAR query[] = {
4163 'S','E','L','E','C','T',' ','*',' ',
4164 'F','R','O','M',' ','`','%','s','`',0 };
4165 MSIQUERY *view = NULL;
4166 DWORD count = 0;
4167 UINT r;
4169 r = MSI_OpenQuery( package->db, &view, query, table );
4170 if (r == ERROR_SUCCESS)
4172 r = MSI_IterateRecords(view, &count, NULL, package);
4173 msiobj_release(&view->hdr);
4176 if (count)
4177 FIXME("%s -> %u ignored %s table values\n",
4178 action, count, debugstr_w(table));
4180 return ERROR_SUCCESS;
4183 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4185 TRACE("%p\n", package);
4186 return ERROR_SUCCESS;
4189 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4191 static const WCHAR table[] =
4192 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4193 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4196 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4198 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4199 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4202 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4204 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4205 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4208 static UINT ACTION_BindImage( MSIPACKAGE *package )
4210 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4211 return msi_unimplemented_action_stub( package, "BindImage", table );
4214 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4216 static const WCHAR table[] = {
4217 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4218 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4221 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4223 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4224 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4227 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4229 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4230 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4233 static UINT ACTION_StartServices( MSIPACKAGE *package )
4235 static const WCHAR table[] = {
4236 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4237 return msi_unimplemented_action_stub( package, "StartServices", table );
4240 static UINT ACTION_StopServices( MSIPACKAGE *package )
4242 static const WCHAR table[] = {
4243 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4244 return msi_unimplemented_action_stub( package, "StopServices", table );
4247 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4249 static const WCHAR table[] = {
4250 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4251 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4254 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4256 static const WCHAR table[] = {
4257 'E','n','v','i','r','o','n','m','e','n','t',0 };
4258 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4261 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4263 static const WCHAR table[] = {
4264 'E','n','v','i','r','o','n','m','e','n','t',0 };
4265 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4268 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4270 static const WCHAR table[] = {
4271 'M','s','i','A','s','s','e','m','b','l','y',0 };
4272 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4275 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4277 static const WCHAR table[] = {
4278 'M','s','i','A','s','s','e','m','b','l','y',0 };
4279 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4282 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4284 static const WCHAR table[] = { 'F','o','n','t',0 };
4285 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4288 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4290 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4291 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4294 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4296 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4297 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4300 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4302 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4303 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4306 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4308 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4309 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4312 static struct _actions StandardActions[] = {
4313 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4314 { szAppSearch, ACTION_AppSearch },
4315 { szBindImage, ACTION_BindImage },
4316 { szCCPSearch, ACTION_CCPSearch},
4317 { szCostFinalize, ACTION_CostFinalize },
4318 { szCostInitialize, ACTION_CostInitialize },
4319 { szCreateFolders, ACTION_CreateFolders },
4320 { szCreateShortcuts, ACTION_CreateShortcuts },
4321 { szDeleteServices, ACTION_DeleteServices },
4322 { szDisableRollback, NULL},
4323 { szDuplicateFiles, ACTION_DuplicateFiles },
4324 { szExecuteAction, ACTION_ExecuteAction },
4325 { szFileCost, ACTION_FileCost },
4326 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4327 { szForceReboot, ACTION_ForceReboot },
4328 { szInstallAdminPackage, NULL},
4329 { szInstallExecute, ACTION_InstallExecute },
4330 { szInstallExecuteAgain, ACTION_InstallExecute },
4331 { szInstallFiles, ACTION_InstallFiles},
4332 { szInstallFinalize, ACTION_InstallFinalize },
4333 { szInstallInitialize, ACTION_InstallInitialize },
4334 { szInstallSFPCatalogFile, NULL},
4335 { szInstallValidate, ACTION_InstallValidate },
4336 { szIsolateComponents, ACTION_IsolateComponents },
4337 { szLaunchConditions, ACTION_LaunchConditions },
4338 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4339 { szMoveFiles, ACTION_MoveFiles },
4340 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4341 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4342 { szInstallODBC, NULL},
4343 { szInstallServices, ACTION_InstallServices },
4344 { szPatchFiles, ACTION_PatchFiles },
4345 { szProcessComponents, ACTION_ProcessComponents },
4346 { szPublishComponents, ACTION_PublishComponents },
4347 { szPublishFeatures, ACTION_PublishFeatures },
4348 { szPublishProduct, ACTION_PublishProduct },
4349 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4350 { szRegisterComPlus, ACTION_RegisterComPlus},
4351 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4352 { szRegisterFonts, ACTION_RegisterFonts },
4353 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4354 { szRegisterProduct, ACTION_RegisterProduct },
4355 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4356 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4357 { szRegisterUser, ACTION_RegisterUser},
4358 { szRemoveDuplicateFiles, NULL},
4359 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4360 { szRemoveExistingProducts, NULL},
4361 { szRemoveFiles, ACTION_RemoveFiles},
4362 { szRemoveFolders, NULL},
4363 { szRemoveIniValues, ACTION_RemoveIniValues },
4364 { szRemoveODBC, NULL},
4365 { szRemoveRegistryValues, NULL},
4366 { szRemoveShortcuts, NULL},
4367 { szResolveSource, ACTION_ResolveSource},
4368 { szRMCCPSearch, ACTION_RMCCPSearch},
4369 { szScheduleReboot, NULL},
4370 { szSelfRegModules, ACTION_SelfRegModules },
4371 { szSelfUnregModules, ACTION_SelfUnregModules },
4372 { szSetODBCFolders, NULL},
4373 { szStartServices, ACTION_StartServices },
4374 { szStopServices, ACTION_StopServices },
4375 { szUnpublishComponents, NULL},
4376 { szUnpublishFeatures, NULL},
4377 { szUnregisterClassInfo, NULL},
4378 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4379 { szUnregisterExtensionInfo, NULL},
4380 { szUnregisterFonts, ACTION_UnregisterFonts },
4381 { szUnregisterMIMEInfo, NULL},
4382 { szUnregisterProgIdInfo, NULL},
4383 { szUnregisterTypeLibraries, NULL},
4384 { szValidateProductID, NULL},
4385 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4386 { szWriteIniValues, ACTION_WriteIniValues },
4387 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4388 { NULL, NULL},