twain_32: Renamed the dlls/twain directory to dlls/twain_32.
[wine/wine-kai.git] / dlls / msi / action.c
blob66d75f9b1d71a4a9046d6e0f61c82b8ab1a05d3c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Pages I need
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
29 #include <stdarg.h>
31 #define COBJMACROS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "wine/debug.h"
38 #include "msidefs.h"
39 #include "msipriv.h"
40 #include "winuser.h"
41 #include "shlobj.h"
42 #include "wine/unicode.h"
43 #include "winver.h"
44 #include "action.h"
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 * Prototypes
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
59 * consts and values used
61 static const WCHAR c_colon[] = {'C',':','\\',0};
63 static const WCHAR szCreateFolders[] =
64 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73 'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] =
77 {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] =
79 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] =
81 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] =
83 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] =
85 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] =
87 {'R','e','g','i','s','t','e','r','T','y','p','e',
88 'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] =
90 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] =
92 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] =
94 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] =
96 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] =
98 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] =
100 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] =
102 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] =
104 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] =
108 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109 'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] =
111 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] =
113 {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 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 int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
297 LPWSTR str = msi_dup_property( package, prop );
298 int val = str ? atoiW( str ) : def;
299 msi_free( str );
300 return val;
303 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
305 LPCWSTR ptr,ptr2;
306 BOOL quote;
307 DWORD len;
308 LPWSTR prop = NULL, val = NULL;
310 if (!szCommandLine)
311 return ERROR_SUCCESS;
313 ptr = szCommandLine;
315 while (*ptr)
317 if (*ptr==' ')
319 ptr++;
320 continue;
323 TRACE("Looking at %s\n",debugstr_w(ptr));
325 ptr2 = strchrW(ptr,'=');
326 if (!ptr2)
328 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
329 break;
332 quote = FALSE;
334 len = ptr2-ptr;
335 prop = msi_alloc((len+1)*sizeof(WCHAR));
336 memcpy(prop,ptr,len*sizeof(WCHAR));
337 prop[len]=0;
338 ptr2++;
340 len = 0;
341 ptr = ptr2;
342 while (*ptr && (quote || (!quote && *ptr!=' ')))
344 if (*ptr == '"')
345 quote = !quote;
346 ptr++;
347 len++;
350 if (*ptr2=='"')
352 ptr2++;
353 len -= 2;
355 val = msi_alloc((len+1)*sizeof(WCHAR));
356 memcpy(val,ptr2,len*sizeof(WCHAR));
357 val[len] = 0;
359 if (lstrlenW(prop) > 0)
361 TRACE("Found commandline property (%s) = (%s)\n",
362 debugstr_w(prop), debugstr_w(val));
363 MSI_SetPropertyW(package,prop,val);
365 msi_free(val);
366 msi_free(prop);
369 return ERROR_SUCCESS;
373 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
375 LPWSTR p, *ret = NULL;
376 UINT count = 0;
378 if (!str)
379 return ret;
381 /* count the number of substrings */
382 for ( p = (LPWSTR)str, count = 0; p; count++ )
384 p = strchrW( p, sep );
385 if (p)
386 p++;
389 /* allocate space for an array of substring pointers and the substrings */
390 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
391 (lstrlenW(str)+1) * sizeof(WCHAR) );
392 if (!ret)
393 return ret;
395 /* copy the string and set the pointers */
396 p = (LPWSTR) &ret[count+1];
397 lstrcpyW( p, str );
398 for( count = 0; (ret[count] = p); count++ )
400 p = strchrW( p, sep );
401 if (p)
402 *p++ = 0;
405 return ret;
408 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
413 HRESULT r;
415 TRACE("%p %s\n", package, debugstr_w(name) );
417 if (*name++ != ':')
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
424 if (SUCCEEDED(r))
426 ret = msi_table_apply_transform( package->db, stg );
427 IStorage_Release( stg );
428 ret = ERROR_SUCCESS;
430 else
431 ERR("failed to open substorage %s\n", debugstr_w(name));
433 return ret;
436 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
438 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
439 LPWSTR guid_list, *guids, product_id;
440 UINT i, ret = ERROR_FUNCTION_FAILED;
442 product_id = msi_dup_property( package, szProdID );
443 if (!product_id)
445 /* FIXME: the property ProductID should be written into the DB somewhere */
446 ERR("no product ID to check\n");
447 return ERROR_SUCCESS;
450 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
451 guids = msi_split_string( guid_list, ';' );
452 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
454 if (!lstrcmpW( guids[i], product_id ))
455 ret = ERROR_SUCCESS;
457 msi_free( guids );
458 msi_free( guid_list );
459 msi_free( product_id );
461 return ret;
464 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
466 MSISUMMARYINFO *si;
467 LPWSTR str, *substorage;
468 UINT i, r = ERROR_SUCCESS;
470 si = MSI_GetSummaryInformationW( patch_db, 0 );
471 if (!si)
472 return ERROR_FUNCTION_FAILED;
474 msi_check_patch_applicable( package, si );
476 /* enumerate the substorage */
477 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
478 substorage = msi_split_string( str, ';' );
479 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
480 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
481 msi_free( substorage );
482 msi_free( str );
484 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
486 msiobj_release( &si->hdr );
488 return r;
491 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
493 MSIDATABASE *patch_db = NULL;
494 UINT r;
496 TRACE("%p %s\n", package, debugstr_w( file ) );
498 /* FIXME:
499 * We probably want to make sure we only open a patch collection here.
500 * Patch collections (.msp) and databases (.msi) have different GUIDs
501 * but currently MSI_OpenDatabaseW will accept both.
503 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
504 if ( r != ERROR_SUCCESS )
506 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
507 return r;
510 msi_parse_patch_summary( package, patch_db );
511 msiobj_release( &patch_db->hdr );
513 return ERROR_SUCCESS;
516 /* get the PATCH property, and apply all the patches it specifies */
517 static UINT msi_apply_patches( MSIPACKAGE *package )
519 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
520 LPWSTR patch_list, *patches;
521 UINT i, r = ERROR_SUCCESS;
523 patch_list = msi_dup_property( package, szPatch );
525 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
527 patches = msi_split_string( patch_list, ';' );
528 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
529 r = msi_apply_patch_package( package, patches[i] );
531 msi_free( patches );
532 msi_free( patch_list );
534 return r;
537 static UINT msi_apply_transforms( MSIPACKAGE *package )
539 static const WCHAR szTransforms[] = {
540 'T','R','A','N','S','F','O','R','M','S',0 };
541 LPWSTR xform_list, *xforms;
542 UINT i, r = ERROR_SUCCESS;
544 xform_list = msi_dup_property( package, szTransforms );
545 xforms = msi_split_string( xform_list, ';' );
547 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
549 if (xforms[i][0] == ':')
550 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
551 else
552 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
555 msi_free( xforms );
556 msi_free( xform_list );
558 return r;
561 /****************************************************
562 * TOP level entry points
563 *****************************************************/
565 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
566 LPCWSTR szCommandLine )
568 UINT rc;
569 BOOL ui = FALSE;
570 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
571 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
572 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
574 MSI_SetPropertyW(package, szAction, szInstall);
576 package->script = msi_alloc(sizeof(MSISCRIPT));
577 memset(package->script,0,sizeof(MSISCRIPT));
579 package->script->InWhatSequence = SEQUENCE_INSTALL;
581 if (szPackagePath)
583 LPWSTR p, check, path;
585 package->PackagePath = strdupW(szPackagePath);
586 path = strdupW(szPackagePath);
587 p = strrchrW(path,'\\');
588 if (p)
590 p++;
591 *p=0;
593 else
595 msi_free(path);
596 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
597 GetCurrentDirectoryW(MAX_PATH,path);
598 strcatW(path,cszbs);
601 check = msi_dup_property( package, cszSourceDir );
602 if (!check)
603 MSI_SetPropertyW(package, cszSourceDir, path);
604 msi_free(check);
605 msi_free(path);
608 msi_parse_command_line( package, szCommandLine );
610 msi_apply_transforms( package );
611 msi_apply_patches( package );
613 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
615 package->script->InWhatSequence |= SEQUENCE_UI;
616 rc = ACTION_ProcessUISequence(package);
617 ui = TRUE;
618 if (rc == ERROR_SUCCESS)
620 package->script->InWhatSequence |= SEQUENCE_EXEC;
621 rc = ACTION_ProcessExecSequence(package,TRUE);
624 else
625 rc = ACTION_ProcessExecSequence(package,FALSE);
627 if (rc == -1)
629 /* install was halted but should be considered a success */
630 rc = ERROR_SUCCESS;
633 package->script->CurrentlyScripting= FALSE;
635 /* process the ending type action */
636 if (rc == ERROR_SUCCESS)
637 ACTION_PerformActionSequence(package,-1,ui);
638 else if (rc == ERROR_INSTALL_USEREXIT)
639 ACTION_PerformActionSequence(package,-2,ui);
640 else if (rc == ERROR_INSTALL_SUSPEND)
641 ACTION_PerformActionSequence(package,-4,ui);
642 else /* failed */
643 ACTION_PerformActionSequence(package,-3,ui);
645 /* finish up running custom actions */
646 ACTION_FinishCustomActions(package);
648 return rc;
651 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
653 UINT rc = ERROR_SUCCESS;
654 MSIRECORD * row = 0;
655 static const WCHAR ExecSeqQuery[] =
656 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
657 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
658 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
659 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
661 static const WCHAR UISeqQuery[] =
662 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
663 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
664 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
665 ' ', '=',' ','%','i',0};
667 if (UI)
668 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
669 else
670 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
672 if (row)
674 LPCWSTR action, cond;
676 TRACE("Running the actions\n");
678 /* check conditions */
679 cond = MSI_RecordGetString(row,2);
680 if (cond)
682 /* this is a hack to skip errors in the condition code */
683 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
684 goto end;
687 action = MSI_RecordGetString(row,1);
688 if (!action)
690 ERR("failed to fetch action\n");
691 rc = ERROR_FUNCTION_FAILED;
692 goto end;
695 if (UI)
696 rc = ACTION_PerformUIAction(package,action);
697 else
698 rc = ACTION_PerformAction(package,action,FALSE);
699 end:
700 msiobj_release(&row->hdr);
702 else
703 rc = ERROR_SUCCESS;
705 return rc;
708 typedef struct {
709 MSIPACKAGE* package;
710 BOOL UI;
711 } iterate_action_param;
713 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
715 iterate_action_param *iap= (iterate_action_param*)param;
716 UINT rc;
717 LPCWSTR cond, action;
719 action = MSI_RecordGetString(row,1);
720 if (!action)
722 ERR("Error is retrieving action name\n");
723 return ERROR_FUNCTION_FAILED;
726 /* check conditions */
727 cond = MSI_RecordGetString(row,2);
728 if (cond)
730 /* this is a hack to skip errors in the condition code */
731 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
733 TRACE("Skipping action: %s (condition is false)\n",
734 debugstr_w(action));
735 return ERROR_SUCCESS;
739 if (iap->UI)
740 rc = ACTION_PerformUIAction(iap->package,action);
741 else
742 rc = ACTION_PerformAction(iap->package,action,FALSE);
744 msi_dialog_check_messages( NULL );
746 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
747 rc = iap->package->CurrentInstallState;
749 if (rc == ERROR_FUNCTION_NOT_CALLED)
750 rc = ERROR_SUCCESS;
752 if (rc != ERROR_SUCCESS)
753 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
755 return rc;
758 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
760 MSIQUERY * view;
761 UINT r;
762 static const WCHAR query[] =
763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
764 '`','%','s','`',
765 ' ','W','H','E','R','E',' ',
766 '`','S','e','q','u','e','n','c','e','`',' ',
767 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
768 '`','S','e','q','u','e','n','c','e','`',0};
769 iterate_action_param iap;
772 * FIXME: probably should be checking UILevel in the
773 * ACTION_PerformUIAction/ACTION_PerformAction
774 * rather than saving the UI level here. Those
775 * two functions can be merged too.
777 iap.package = package;
778 iap.UI = TRUE;
780 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
782 r = MSI_OpenQuery( package->db, &view, query, szTable );
783 if (r == ERROR_SUCCESS)
785 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
786 msiobj_release(&view->hdr);
789 return r;
792 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
794 MSIQUERY * view;
795 UINT rc;
796 static const WCHAR ExecSeqQuery[] =
797 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
798 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
799 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
800 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
801 'O','R','D','E','R',' ', 'B','Y',' ',
802 '`','S','e','q','u','e','n','c','e','`',0 };
803 MSIRECORD * row = 0;
804 static const WCHAR IVQuery[] =
805 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
806 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
807 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
808 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
809 ' ','\'', 'I','n','s','t','a','l','l',
810 'V','a','l','i','d','a','t','e','\'', 0};
811 INT seq = 0;
812 iterate_action_param iap;
814 iap.package = package;
815 iap.UI = FALSE;
817 if (package->script->ExecuteSequenceRun)
819 TRACE("Execute Sequence already Run\n");
820 return ERROR_SUCCESS;
823 package->script->ExecuteSequenceRun = TRUE;
825 /* get the sequence number */
826 if (UIran)
828 row = MSI_QueryGetRecord(package->db, IVQuery);
829 if( !row )
830 return ERROR_FUNCTION_FAILED;
831 seq = MSI_RecordGetInteger(row,1);
832 msiobj_release(&row->hdr);
835 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
836 if (rc == ERROR_SUCCESS)
838 TRACE("Running the actions\n");
840 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
841 msiobj_release(&view->hdr);
844 return rc;
847 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
849 MSIQUERY * view;
850 UINT rc;
851 static const WCHAR ExecSeqQuery [] =
852 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
853 '`','I','n','s','t','a','l','l',
854 'U','I','S','e','q','u','e','n','c','e','`',
855 ' ','W','H','E','R','E',' ',
856 '`','S','e','q','u','e','n','c','e','`',' ',
857 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
858 '`','S','e','q','u','e','n','c','e','`',0};
859 iterate_action_param iap;
861 iap.package = package;
862 iap.UI = TRUE;
864 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
866 if (rc == ERROR_SUCCESS)
868 TRACE("Running the actions\n");
870 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
871 msiobj_release(&view->hdr);
874 return rc;
877 /********************************************************
878 * ACTION helper functions and functions that perform the actions
879 *******************************************************/
880 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
881 UINT* rc, BOOL force )
883 BOOL ret = FALSE;
884 BOOL run = force;
885 int i;
887 if (!package)
889 ERR("package was null!\n");
890 return FALSE;
893 if (!run && !package->script->CurrentlyScripting)
894 run = TRUE;
896 if (!run)
898 if (strcmpW(action,szInstallFinalize) == 0 ||
899 strcmpW(action,szInstallExecute) == 0 ||
900 strcmpW(action,szInstallExecuteAgain) == 0)
901 run = TRUE;
904 i = 0;
905 while (StandardActions[i].action != NULL)
907 if (strcmpW(StandardActions[i].action, action)==0)
909 if (!run)
911 ui_actioninfo(package, action, TRUE, 0);
912 *rc = schedule_action(package,INSTALL_SCRIPT,action);
913 ui_actioninfo(package, action, FALSE, *rc);
915 else
917 ui_actionstart(package, action);
918 if (StandardActions[i].handler)
920 *rc = StandardActions[i].handler(package);
922 else
924 FIXME("unhandled standard action %s\n",debugstr_w(action));
925 *rc = ERROR_SUCCESS;
928 ret = TRUE;
929 break;
931 i++;
933 return ret;
936 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
937 UINT* rc, BOOL force )
939 BOOL ret=FALSE;
940 UINT arc;
942 arc = ACTION_CustomAction(package,action, force);
944 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
946 *rc = arc;
947 ret = TRUE;
949 return ret;
953 * A lot of actions are really important even if they don't do anything
954 * explicit... Lots of properties are set at the beginning of the installation
955 * CostFinalize does a bunch of work to translate the directories and such
957 * But until I get write access to the database that is hard, so I am going to
958 * hack it to see if I can get something to run.
960 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
962 UINT rc = ERROR_SUCCESS;
963 BOOL handled;
965 TRACE("Performing action (%s)\n",debugstr_w(action));
967 handled = ACTION_HandleStandardAction(package, action, &rc, force);
969 if (!handled)
970 handled = ACTION_HandleCustomAction(package, action, &rc, force);
972 if (!handled)
974 FIXME("unhandled msi action %s\n",debugstr_w(action));
975 rc = ERROR_FUNCTION_NOT_CALLED;
978 return rc;
981 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
983 UINT rc = ERROR_SUCCESS;
984 BOOL handled = FALSE;
986 TRACE("Performing action (%s)\n",debugstr_w(action));
988 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
990 if (!handled)
991 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
993 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
994 handled = TRUE;
996 if (!handled)
998 FIXME("unhandled msi action %s\n",debugstr_w(action));
999 rc = ERROR_FUNCTION_NOT_CALLED;
1002 return rc;
1007 * Actual Action Handlers
1010 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1012 MSIPACKAGE *package = (MSIPACKAGE*)param;
1013 LPCWSTR dir;
1014 LPWSTR full_path;
1015 MSIRECORD *uirow;
1016 MSIFOLDER *folder;
1018 dir = MSI_RecordGetString(row,1);
1019 if (!dir)
1021 ERR("Unable to get folder id\n");
1022 return ERROR_SUCCESS;
1025 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1026 if (!full_path)
1028 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1029 return ERROR_SUCCESS;
1032 TRACE("Folder is %s\n",debugstr_w(full_path));
1034 /* UI stuff */
1035 uirow = MSI_CreateRecord(1);
1036 MSI_RecordSetStringW(uirow,1,full_path);
1037 ui_actiondata(package,szCreateFolders,uirow);
1038 msiobj_release( &uirow->hdr );
1040 if (folder->State == 0)
1041 create_full_pathW(full_path);
1043 folder->State = 3;
1045 msi_free(full_path);
1046 return ERROR_SUCCESS;
1049 /* FIXME: probably should merge this with the above function */
1050 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1052 UINT rc = ERROR_SUCCESS;
1053 MSIFOLDER *folder;
1054 LPWSTR install_path;
1056 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1057 if (!install_path)
1058 return ERROR_FUNCTION_FAILED;
1060 /* create the path */
1061 if (folder->State == 0)
1063 create_full_pathW(install_path);
1064 folder->State = 2;
1066 msi_free(install_path);
1068 return rc;
1071 UINT msi_create_component_directories( MSIPACKAGE *package )
1073 MSICOMPONENT *comp;
1075 /* create all the folders required by the components are going to install */
1076 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1078 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1079 continue;
1080 msi_create_directory( package, comp->Directory );
1083 return ERROR_SUCCESS;
1087 * Also we cannot enable/disable components either, so for now I am just going
1088 * to do all the directories for all the components.
1090 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1092 static const WCHAR ExecSeqQuery[] =
1093 {'S','E','L','E','C','T',' ',
1094 '`','D','i','r','e','c','t','o','r','y','_','`',
1095 ' ','F','R','O','M',' ',
1096 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1097 UINT rc;
1098 MSIQUERY *view;
1100 /* create all the empty folders specified in the CreateFolder table */
1101 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1102 if (rc != ERROR_SUCCESS)
1103 return ERROR_SUCCESS;
1105 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1106 msiobj_release(&view->hdr);
1108 msi_create_component_directories( package );
1110 return rc;
1113 static MSICOMPONENT* load_component( MSIRECORD * row )
1115 MSICOMPONENT *comp;
1117 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1118 if (!comp)
1119 return comp;
1121 /* fill in the data */
1122 comp->Component = msi_dup_record_field( row, 1 );
1124 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1126 comp->ComponentId = msi_dup_record_field( row, 2 );
1127 comp->Directory = msi_dup_record_field( row, 3 );
1128 comp->Attributes = MSI_RecordGetInteger(row,4);
1129 comp->Condition = msi_dup_record_field( row, 5 );
1130 comp->KeyPath = msi_dup_record_field( row, 6 );
1132 comp->Installed = INSTALLSTATE_ABSENT;
1133 comp->Action = INSTALLSTATE_UNKNOWN;
1134 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
1136 comp->Enabled = TRUE;
1138 return comp;
1141 typedef struct {
1142 MSIPACKAGE *package;
1143 MSIFEATURE *feature;
1144 } _ilfs;
1146 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1148 ComponentList *cl;
1150 cl = msi_alloc( sizeof (*cl) );
1151 if ( !cl )
1152 return ERROR_NOT_ENOUGH_MEMORY;
1153 cl->component = comp;
1154 list_add_tail( &feature->Components, &cl->entry );
1156 return ERROR_SUCCESS;
1159 static UINT iterate_component_check( MSIRECORD *row, LPVOID param )
1161 _ilfs* ilfs= (_ilfs*)param;
1162 MSIPACKAGE *package = ilfs->package;
1163 MSIFEATURE *feature = ilfs->feature;
1164 MSICOMPONENT *comp;
1166 comp = load_component( row );
1167 if (!comp)
1168 return ERROR_FUNCTION_FAILED;
1170 list_add_tail( &package->components, &comp->entry );
1171 add_feature_component( feature, comp );
1173 TRACE("Loaded new component %p\n", comp);
1175 return ERROR_SUCCESS;
1178 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1180 _ilfs* ilfs= (_ilfs*)param;
1181 LPCWSTR component;
1182 DWORD rc;
1183 MSICOMPONENT *comp;
1184 MSIQUERY * view;
1185 static const WCHAR Query[] =
1186 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1187 '`','C','o','m','p','o','n','e','n','t','`',' ',
1188 'W','H','E','R','E',' ',
1189 '`','C','o','m','p','o','n','e','n','t','`',' ',
1190 '=','\'','%','s','\'',0};
1192 component = MSI_RecordGetString(row,1);
1194 /* check to see if the component is already loaded */
1195 comp = get_loaded_component( ilfs->package, component );
1196 if (comp)
1198 TRACE("Component %s already loaded\n", debugstr_w(component) );
1199 add_feature_component( ilfs->feature, comp );
1200 return ERROR_SUCCESS;
1203 rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
1204 if (rc != ERROR_SUCCESS)
1205 return ERROR_SUCCESS;
1207 rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
1208 msiobj_release( &view->hdr );
1210 return ERROR_SUCCESS;
1213 static UINT load_feature(MSIRECORD * row, LPVOID param)
1215 MSIPACKAGE* package = (MSIPACKAGE*)param;
1216 MSIFEATURE* feature;
1217 static const WCHAR Query1[] =
1218 {'S','E','L','E','C','T',' ',
1219 '`','C','o','m','p','o','n','e','n','t','_','`',
1220 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1221 'C','o','m','p','o','n','e','n','t','s','`',' ',
1222 'W','H','E','R','E',' ',
1223 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1224 MSIQUERY * view;
1225 UINT rc;
1226 _ilfs ilfs;
1228 /* fill in the data */
1230 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1231 if (!feature)
1232 return ERROR_NOT_ENOUGH_MEMORY;
1234 list_init( &feature->Components );
1236 feature->Feature = msi_dup_record_field( row, 1 );
1238 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1240 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1241 feature->Title = msi_dup_record_field( row, 3 );
1242 feature->Description = msi_dup_record_field( row, 4 );
1244 if (!MSI_RecordIsNull(row,5))
1245 feature->Display = MSI_RecordGetInteger(row,5);
1247 feature->Level= MSI_RecordGetInteger(row,6);
1248 feature->Directory = msi_dup_record_field( row, 7 );
1249 feature->Attributes = MSI_RecordGetInteger(row,8);
1251 feature->Installed = INSTALLSTATE_ABSENT;
1252 feature->Action = INSTALLSTATE_UNKNOWN;
1253 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1255 list_add_tail( &package->features, &feature->entry );
1257 /* load feature components */
1259 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1260 if (rc != ERROR_SUCCESS)
1261 return ERROR_SUCCESS;
1263 ilfs.package = package;
1264 ilfs.feature = feature;
1266 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1267 msiobj_release(&view->hdr);
1269 return ERROR_SUCCESS;
1272 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1274 if (!p)
1275 return p;
1276 p = strchrW(p, ch);
1277 if (!p)
1278 return p;
1279 *p = 0;
1280 return p+1;
1283 static UINT load_file(MSIRECORD *row, LPVOID param)
1285 MSIPACKAGE* package = (MSIPACKAGE*)param;
1286 LPCWSTR component;
1287 MSIFILE *file;
1289 /* fill in the data */
1291 file = msi_alloc_zero( sizeof (MSIFILE) );
1292 if (!file)
1293 return ERROR_NOT_ENOUGH_MEMORY;
1295 file->File = msi_dup_record_field( row, 1 );
1297 component = MSI_RecordGetString( row, 2 );
1298 file->Component = get_loaded_component( package, component );
1300 if (!file->Component)
1301 ERR("Unfound Component %s\n",debugstr_w(component));
1303 file->FileName = msi_dup_record_field( row, 3 );
1304 reduce_to_longfilename( file->FileName );
1306 file->ShortName = msi_dup_record_field( row, 3 );
1307 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1309 file->FileSize = MSI_RecordGetInteger( row, 4 );
1310 file->Version = msi_dup_record_field( row, 5 );
1311 file->Language = msi_dup_record_field( row, 6 );
1312 file->Attributes = MSI_RecordGetInteger( row, 7 );
1313 file->Sequence = MSI_RecordGetInteger( row, 8 );
1315 file->state = msifs_invalid;
1317 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1319 list_add_tail( &package->files, &file->entry );
1321 return ERROR_SUCCESS;
1324 static UINT load_all_files(MSIPACKAGE *package)
1326 MSIQUERY * view;
1327 UINT rc;
1328 static const WCHAR Query[] =
1329 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1330 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1331 '`','S','e','q','u','e','n','c','e','`', 0};
1333 if (!package)
1334 return ERROR_INVALID_HANDLE;
1336 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1337 if (rc != ERROR_SUCCESS)
1338 return ERROR_SUCCESS;
1340 rc = MSI_IterateRecords(view, NULL, load_file, package);
1341 msiobj_release(&view->hdr);
1343 return ERROR_SUCCESS;
1348 * I am not doing any of the costing functionality yet.
1349 * Mostly looking at doing the Component and Feature loading
1351 * The native MSI does A LOT of modification to tables here. Mostly adding
1352 * a lot of temporary columns to the Feature and Component tables.
1354 * note: Native msi also tracks the short filename. But I am only going to
1355 * track the long ones. Also looking at this directory table
1356 * it appears that the directory table does not get the parents
1357 * resolved base on property only based on their entries in the
1358 * directory table.
1360 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1362 MSIQUERY * view;
1363 UINT rc;
1364 static const WCHAR Query_all[] =
1365 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1366 '`','F','e','a','t','u','r','e','`',0};
1367 static const WCHAR szCosting[] =
1368 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1369 static const WCHAR szZero[] = { '0', 0 };
1371 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1372 return ERROR_SUCCESS;
1374 MSI_SetPropertyW(package, szCosting, szZero);
1375 MSI_SetPropertyW(package, cszRootDrive , c_colon);
1377 rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1378 if (rc != ERROR_SUCCESS)
1379 return rc;
1381 rc = MSI_IterateRecords(view, NULL, load_feature, package);
1382 msiobj_release(&view->hdr);
1384 load_all_files(package);
1386 return ERROR_SUCCESS;
1389 static UINT execute_script(MSIPACKAGE *package, UINT script )
1391 int i;
1392 UINT rc = ERROR_SUCCESS;
1394 TRACE("Executing Script %i\n",script);
1396 if (!package->script)
1398 ERR("no script!\n");
1399 return ERROR_FUNCTION_FAILED;
1402 for (i = 0; i < package->script->ActionCount[script]; i++)
1404 LPWSTR action;
1405 action = package->script->Actions[script][i];
1406 ui_actionstart(package, action);
1407 TRACE("Executing Action (%s)\n",debugstr_w(action));
1408 rc = ACTION_PerformAction(package, action, TRUE);
1409 msi_free(package->script->Actions[script][i]);
1410 if (rc != ERROR_SUCCESS)
1411 break;
1413 msi_free(package->script->Actions[script]);
1415 package->script->ActionCount[script] = 0;
1416 package->script->Actions[script] = NULL;
1417 return rc;
1420 static UINT ACTION_FileCost(MSIPACKAGE *package)
1422 return ERROR_SUCCESS;
1425 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1427 static const WCHAR Query[] =
1428 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1429 '`','D','i','r','e','c', 't','o','r','y','`',' ',
1430 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1431 ' ','=',' ','\'','%','s','\'',
1433 static const WCHAR szDot[] = { '.',0 };
1434 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1435 LPCWSTR parent;
1436 MSIRECORD *row;
1437 MSIFOLDER *folder;
1439 TRACE("Looking for dir %s\n",debugstr_w(dir));
1441 folder = get_loaded_folder( package, dir );
1442 if (folder)
1443 return folder;
1445 TRACE("Working to load %s\n",debugstr_w(dir));
1447 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1448 if (!folder)
1449 return NULL;
1451 folder->Directory = strdupW(dir);
1453 row = MSI_QueryGetRecord(package->db, Query, dir);
1454 if (!row)
1455 return NULL;
1457 p = msi_dup_record_field(row, 3);
1459 /* split src and target dir */
1460 tgt_short = p;
1461 src_short = folder_split_path( p, ':' );
1463 /* split the long and short pathes */
1464 tgt_long = folder_split_path( tgt_short, '|' );
1465 src_long = folder_split_path( src_short, '|' );
1467 /* check for root dirs */
1468 if (!lstrcmpW(szDot, tgt_short))
1469 tgt_short = NULL;
1470 if (!lstrcmpW(szDot, tgt_long))
1471 tgt_long = NULL;
1473 if (!tgt_long)
1474 tgt_long = tgt_short;
1475 if (!src_short)
1476 src_short = tgt_long;
1477 if (!src_long)
1478 src_long = src_short;
1480 /* FIXME: use the target short path too */
1481 folder->TargetDefault = strdupW(tgt_long);
1482 folder->SourceShortPath = strdupW(src_long);
1483 folder->SourceLongPath = strdupW(src_long);
1484 msi_free(p);
1486 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1487 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1488 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1490 parent = MSI_RecordGetString(row, 2);
1491 if (parent)
1493 folder->Parent = load_folder( package, parent );
1494 if ( folder->Parent )
1495 TRACE("loaded parent %p %s\n", folder->Parent,
1496 debugstr_w(folder->Parent->Directory));
1497 else
1498 ERR("failed to load parent folder %s\n", debugstr_w(parent));
1501 folder->Property = msi_dup_property( package, dir );
1503 msiobj_release(&row->hdr);
1505 list_add_tail( &package->folders, &folder->entry );
1507 TRACE("%s returning %p\n",debugstr_w(dir),folder);
1509 return folder;
1512 /* scan for and update current install states */
1513 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1515 MSICOMPONENT *comp;
1516 MSIFEATURE *feature;
1518 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1520 INSTALLSTATE res;
1521 res = MsiGetComponentPathW( package->ProductCode,
1522 comp->ComponentId, NULL, NULL);
1523 if (res < 0)
1524 res = INSTALLSTATE_ABSENT;
1525 comp->Installed = res;
1528 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1530 ComponentList *cl;
1531 INSTALLSTATE res = -10;
1533 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1535 comp= cl->component;
1537 if (res == -10)
1538 res = comp->Installed;
1539 else
1541 if (res == comp->Installed)
1542 continue;
1544 if (res != comp->Installed)
1545 res = INSTALLSTATE_INCOMPLETE;
1548 feature->Installed = res;
1552 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1553 INSTALLSTATE state)
1555 static const WCHAR all[]={'A','L','L',0};
1556 LPWSTR override;
1557 MSIFEATURE *feature;
1559 override = msi_dup_property( package, property );
1560 if (!override)
1561 return FALSE;
1563 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1565 if (strcmpiW(override,all)==0)
1567 feature->ActionRequest= state;
1568 feature->Action = state;
1570 else
1572 LPWSTR ptr = override;
1573 LPWSTR ptr2 = strchrW(override,',');
1575 while (ptr)
1577 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1578 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1580 feature->ActionRequest= state;
1581 feature->Action = state;
1582 break;
1584 if (ptr2)
1586 ptr=ptr2+1;
1587 ptr2 = strchrW(ptr,',');
1589 else
1590 break;
1594 msi_free(override);
1596 return TRUE;
1599 static UINT SetFeatureStates(MSIPACKAGE *package)
1601 int install_level;
1602 static const WCHAR szlevel[] =
1603 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1604 static const WCHAR szAddLocal[] =
1605 {'A','D','D','L','O','C','A','L',0};
1606 static const WCHAR szRemove[] =
1607 {'R','E','M','O','V','E',0};
1608 static const WCHAR szReinstall[] =
1609 {'R','E','I','N','S','T','A','L','L',0};
1610 BOOL override = FALSE;
1611 MSICOMPONENT* component;
1612 MSIFEATURE *feature;
1615 /* I do not know if this is where it should happen.. but */
1617 TRACE("Checking Install Level\n");
1619 install_level = msi_get_property_int( package, szlevel, 1 );
1621 /* ok hereis the _real_ rub
1622 * all these activation/deactivation things happen in order and things
1623 * later on the list override things earlier on the list.
1624 * 1) INSTALLLEVEL processing
1625 * 2) ADDLOCAL
1626 * 3) REMOVE
1627 * 4) ADDSOURCE
1628 * 5) ADDDEFAULT
1629 * 6) REINSTALL
1630 * 7) COMPADDLOCAL
1631 * 8) COMPADDSOURCE
1632 * 9) FILEADDLOCAL
1633 * 10) FILEADDSOURCE
1634 * 11) FILEADDDEFAULT
1635 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1636 * ignored for all the features. seems strange, especially since it is not
1637 * documented anywhere, but it is how it works.
1639 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1640 * REMOVE are the big ones, since we don't handle administrative installs
1641 * yet anyway.
1643 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1644 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1645 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1647 if (!override)
1649 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1651 BOOL feature_state = ((feature->Level > 0) &&
1652 (feature->Level <= install_level));
1654 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1656 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1658 feature->ActionRequest = INSTALLSTATE_SOURCE;
1659 feature->Action = INSTALLSTATE_SOURCE;
1661 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1663 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1664 feature->Action = INSTALLSTATE_ADVERTISED;
1666 else
1668 feature->ActionRequest = INSTALLSTATE_LOCAL;
1669 feature->Action = INSTALLSTATE_LOCAL;
1674 else
1676 /* set the Preselected Property */
1677 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1678 static const WCHAR szOne[] = { '1', 0 };
1680 MSI_SetPropertyW(package,szPreselected,szOne);
1684 * now we want to enable or disable components base on feature
1687 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1689 ComponentList *cl;
1691 TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1692 debugstr_w(feature->Feature), feature->Installed, feature->Action,
1693 feature->ActionRequest);
1695 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1697 component = cl->component;
1699 if (!component->Enabled)
1701 component->Action = INSTALLSTATE_UNKNOWN;
1702 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1704 else
1706 if (feature->Action == INSTALLSTATE_LOCAL)
1708 component->Action = INSTALLSTATE_LOCAL;
1709 component->ActionRequest = INSTALLSTATE_LOCAL;
1711 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
1713 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1714 (component->Action == INSTALLSTATE_ABSENT) ||
1715 (component->Action == INSTALLSTATE_ADVERTISED))
1718 component->Action = INSTALLSTATE_SOURCE;
1719 component->ActionRequest = INSTALLSTATE_SOURCE;
1722 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1724 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1725 (component->Action == INSTALLSTATE_ABSENT))
1728 component->Action = INSTALLSTATE_ADVERTISED;
1729 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1732 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1734 if (component->Action == INSTALLSTATE_UNKNOWN)
1736 component->Action = INSTALLSTATE_ABSENT;
1737 component->ActionRequest = INSTALLSTATE_ABSENT;
1744 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1746 TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1747 debugstr_w(component->Component), component->Installed,
1748 component->Action, component->ActionRequest);
1752 return ERROR_SUCCESS;
1755 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1757 MSIPACKAGE *package = (MSIPACKAGE*)param;
1758 LPCWSTR name;
1759 LPWSTR path;
1761 name = MSI_RecordGetString(row,1);
1763 /* This helper function now does ALL the work */
1764 TRACE("Dir %s ...\n",debugstr_w(name));
1765 load_folder(package,name);
1766 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1767 TRACE("resolves to %s\n",debugstr_w(path));
1768 msi_free(path);
1770 return ERROR_SUCCESS;
1773 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1775 MSIPACKAGE *package = (MSIPACKAGE*)param;
1776 LPCWSTR name;
1777 MSIFEATURE *feature;
1779 name = MSI_RecordGetString( row, 1 );
1781 feature = get_loaded_feature( package, name );
1782 if (!feature)
1783 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1784 else
1786 LPCWSTR Condition;
1787 Condition = MSI_RecordGetString(row,3);
1789 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1791 int level = MSI_RecordGetInteger(row,2);
1792 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1793 feature->Level = level;
1796 return ERROR_SUCCESS;
1801 * A lot is done in this function aside from just the costing.
1802 * The costing needs to be implemented at some point but for now I am going
1803 * to focus on the directory building
1806 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1808 static const WCHAR ExecSeqQuery[] =
1809 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1810 '`','D','i','r','e','c','t','o','r','y','`',0};
1811 static const WCHAR ConditionQuery[] =
1812 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1813 '`','C','o','n','d','i','t','i','o','n','`',0};
1814 static const WCHAR szCosting[] =
1815 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1816 static const WCHAR szlevel[] =
1817 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1818 static const WCHAR szOne[] = { '1', 0 };
1819 MSICOMPONENT *comp;
1820 MSIFILE *file;
1821 UINT rc;
1822 MSIQUERY * view;
1823 LPWSTR level;
1825 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1826 return ERROR_SUCCESS;
1828 TRACE("Building Directory properties\n");
1830 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1831 if (rc == ERROR_SUCCESS)
1833 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1834 package);
1835 msiobj_release(&view->hdr);
1838 TRACE("File calculations\n");
1840 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1842 MSICOMPONENT* comp = file->Component;
1843 LPWSTR p;
1845 if (!comp)
1846 continue;
1848 /* calculate target */
1849 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1851 msi_free(file->TargetPath);
1853 TRACE("file %s is named %s\n",
1854 debugstr_w(file->File),debugstr_w(file->FileName));
1856 file->TargetPath = build_directory_name(2, p, file->FileName);
1858 msi_free(p);
1860 TRACE("file %s resolves to %s\n",
1861 debugstr_w(file->File),debugstr_w(file->TargetPath));
1863 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1865 file->state = msifs_missing;
1866 comp->Cost += file->FileSize;
1867 continue;
1870 if (file->Version)
1872 DWORD handle;
1873 DWORD versize;
1874 UINT sz;
1875 LPVOID version;
1876 static WCHAR name[] = {'\\',0};
1877 static const WCHAR name_fmt[] =
1878 {'%','u','.','%','u','.','%','u','.','%','u',0};
1879 WCHAR filever[0x100];
1880 VS_FIXEDFILEINFO *lpVer;
1882 TRACE("Version comparison..\n");
1883 versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
1884 version = msi_alloc(versize);
1885 GetFileVersionInfoW(file->TargetPath, 0, versize, version);
1887 VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
1889 sprintfW(filever,name_fmt,
1890 HIWORD(lpVer->dwFileVersionMS),
1891 LOWORD(lpVer->dwFileVersionMS),
1892 HIWORD(lpVer->dwFileVersionLS),
1893 LOWORD(lpVer->dwFileVersionLS));
1895 TRACE("new %s old %s\n", debugstr_w(file->Version),
1896 debugstr_w(filever));
1897 if (strcmpiW(filever,file->Version)<0)
1899 file->state = msifs_overwrite;
1900 /* FIXME: cost should be diff in size */
1901 comp->Cost += file->FileSize;
1903 else
1904 file->state = msifs_present;
1905 msi_free(version);
1907 else
1908 file->state = msifs_present;
1911 TRACE("Evaluating Condition Table\n");
1913 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1914 if (rc == ERROR_SUCCESS)
1916 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1917 package);
1918 msiobj_release(&view->hdr);
1921 TRACE("Enabling or Disabling Components\n");
1922 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1924 if (comp->Condition)
1926 if (MSI_EvaluateConditionW(package,
1927 comp->Condition) == MSICONDITION_FALSE)
1929 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
1930 comp->Enabled = FALSE;
1935 MSI_SetPropertyW(package,szCosting,szOne);
1936 /* set default run level if not set */
1937 level = msi_dup_property( package, szlevel );
1938 if (!level)
1939 MSI_SetPropertyW(package,szlevel, szOne);
1940 msi_free(level);
1942 ACTION_UpdateInstallStates(package);
1944 return SetFeatureStates(package);
1947 /* OK this value is "interpreted" and then formatted based on the
1948 first few characters */
1949 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
1950 DWORD *size)
1952 LPSTR data = NULL;
1953 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
1955 if (value[1]=='x')
1957 LPWSTR ptr;
1958 CHAR byte[5];
1959 LPWSTR deformated = NULL;
1960 int count;
1962 deformat_string(package, &value[2], &deformated);
1964 /* binary value type */
1965 ptr = deformated;
1966 *type = REG_BINARY;
1967 if (strlenW(ptr)%2)
1968 *size = (strlenW(ptr)/2)+1;
1969 else
1970 *size = strlenW(ptr)/2;
1972 data = msi_alloc(*size);
1974 byte[0] = '0';
1975 byte[1] = 'x';
1976 byte[4] = 0;
1977 count = 0;
1978 /* if uneven pad with a zero in front */
1979 if (strlenW(ptr)%2)
1981 byte[2]= '0';
1982 byte[3]= *ptr;
1983 ptr++;
1984 data[count] = (BYTE)strtol(byte,NULL,0);
1985 count ++;
1986 TRACE("Uneven byte count\n");
1988 while (*ptr)
1990 byte[2]= *ptr;
1991 ptr++;
1992 byte[3]= *ptr;
1993 ptr++;
1994 data[count] = (BYTE)strtol(byte,NULL,0);
1995 count ++;
1997 msi_free(deformated);
1999 TRACE("Data %li bytes(%i)\n",*size,count);
2001 else
2003 LPWSTR deformated;
2004 LPWSTR p;
2005 DWORD d = 0;
2006 deformat_string(package, &value[1], &deformated);
2008 *type=REG_DWORD;
2009 *size = sizeof(DWORD);
2010 data = msi_alloc(*size);
2011 p = deformated;
2012 if (*p == '-')
2013 p++;
2014 while (*p)
2016 if ( (*p < '0') || (*p > '9') )
2017 break;
2018 d *= 10;
2019 d += (*p - '0');
2020 p++;
2022 if (deformated[0] == '-')
2023 d = -d;
2024 *(LPDWORD)data = d;
2025 TRACE("DWORD %li\n",*(LPDWORD)data);
2027 msi_free(deformated);
2030 else
2032 static const WCHAR szMulti[] = {'[','~',']',0};
2033 LPCWSTR ptr;
2034 *type=REG_SZ;
2036 if (value[0]=='#')
2038 if (value[1]=='%')
2040 ptr = &value[2];
2041 *type=REG_EXPAND_SZ;
2043 else
2044 ptr = &value[1];
2046 else
2047 ptr=value;
2049 if (strstrW(value,szMulti))
2050 *type = REG_MULTI_SZ;
2052 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2054 return data;
2057 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2059 MSIPACKAGE *package = (MSIPACKAGE*)param;
2060 static const WCHAR szHCR[] =
2061 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2062 'R','O','O','T','\\',0};
2063 static const WCHAR szHCU[] =
2064 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2065 'U','S','E','R','\\',0};
2066 static const WCHAR szHLM[] =
2067 {'H','K','E','Y','_','L','O','C','A','L','_',
2068 'M','A','C','H','I','N','E','\\',0};
2069 static const WCHAR szHU[] =
2070 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2072 LPSTR value_data = NULL;
2073 HKEY root_key, hkey;
2074 DWORD type,size;
2075 LPWSTR deformated;
2076 LPCWSTR szRoot, component, name, key, value;
2077 MSICOMPONENT *comp;
2078 MSIRECORD * uirow;
2079 LPWSTR uikey;
2080 INT root;
2081 BOOL check_first = FALSE;
2082 UINT rc;
2084 ui_progress(package,2,0,0,0);
2086 value = NULL;
2087 key = NULL;
2088 uikey = NULL;
2089 name = NULL;
2091 component = MSI_RecordGetString(row, 6);
2092 comp = get_loaded_component(package,component);
2093 if (!comp)
2094 return ERROR_SUCCESS;
2096 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2098 TRACE("Skipping write due to disabled component %s\n",
2099 debugstr_w(component));
2101 comp->Action = comp->Installed;
2103 return ERROR_SUCCESS;
2106 comp->Action = INSTALLSTATE_LOCAL;
2108 name = MSI_RecordGetString(row, 4);
2109 if( MSI_RecordIsNull(row,5) && name )
2111 /* null values can have special meanings */
2112 if (name[0]=='-' && name[1] == 0)
2113 return ERROR_SUCCESS;
2114 else if ((name[0]=='+' && name[1] == 0) ||
2115 (name[0] == '*' && name[1] == 0))
2116 name = NULL;
2117 check_first = TRUE;
2120 root = MSI_RecordGetInteger(row,2);
2121 key = MSI_RecordGetString(row, 3);
2123 /* get the root key */
2124 switch (root)
2126 case -1:
2128 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2129 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2130 if (all_users && all_users[0] == '1')
2132 root_key = HKEY_LOCAL_MACHINE;
2133 szRoot = szHLM;
2135 else
2137 root_key = HKEY_CURRENT_USER;
2138 szRoot = szHCU;
2140 msi_free(all_users);
2142 break;
2143 case 0: root_key = HKEY_CLASSES_ROOT;
2144 szRoot = szHCR;
2145 break;
2146 case 1: root_key = HKEY_CURRENT_USER;
2147 szRoot = szHCU;
2148 break;
2149 case 2: root_key = HKEY_LOCAL_MACHINE;
2150 szRoot = szHLM;
2151 break;
2152 case 3: root_key = HKEY_USERS;
2153 szRoot = szHU;
2154 break;
2155 default:
2156 ERR("Unknown root %i\n",root);
2157 root_key=NULL;
2158 szRoot = NULL;
2159 break;
2161 if (!root_key)
2162 return ERROR_SUCCESS;
2164 deformat_string(package, key , &deformated);
2165 size = strlenW(deformated) + strlenW(szRoot) + 1;
2166 uikey = msi_alloc(size*sizeof(WCHAR));
2167 strcpyW(uikey,szRoot);
2168 strcatW(uikey,deformated);
2170 if (RegCreateKeyW( root_key, deformated, &hkey))
2172 ERR("Could not create key %s\n",debugstr_w(deformated));
2173 msi_free(deformated);
2174 msi_free(uikey);
2175 return ERROR_SUCCESS;
2177 msi_free(deformated);
2179 value = MSI_RecordGetString(row,5);
2180 if (value)
2181 value_data = parse_value(package, value, &type, &size);
2182 else
2184 static const WCHAR szEmpty[] = {0};
2185 value_data = (LPSTR)strdupW(szEmpty);
2186 size = 0;
2187 type = REG_SZ;
2190 deformat_string(package, name, &deformated);
2192 /* get the double nulls to terminate SZ_MULTI */
2193 if (type == REG_MULTI_SZ)
2194 size +=sizeof(WCHAR);
2196 if (!check_first)
2198 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2199 debugstr_w(uikey));
2200 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2202 else
2204 DWORD sz = 0;
2205 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2206 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2208 TRACE("value %s of %s checked already exists\n",
2209 debugstr_w(deformated), debugstr_w(uikey));
2211 else
2213 TRACE("Checked and setting value %s of %s\n",
2214 debugstr_w(deformated), debugstr_w(uikey));
2215 if (deformated || size)
2216 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2219 RegCloseKey(hkey);
2221 uirow = MSI_CreateRecord(3);
2222 MSI_RecordSetStringW(uirow,2,deformated);
2223 MSI_RecordSetStringW(uirow,1,uikey);
2225 if (type == REG_SZ)
2226 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2227 else
2228 MSI_RecordSetStringW(uirow,3,value);
2230 ui_actiondata(package,szWriteRegistryValues,uirow);
2231 msiobj_release( &uirow->hdr );
2233 msi_free(value_data);
2234 msi_free(deformated);
2235 msi_free(uikey);
2237 return ERROR_SUCCESS;
2240 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2242 UINT rc;
2243 MSIQUERY * view;
2244 static const WCHAR ExecSeqQuery[] =
2245 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2246 '`','R','e','g','i','s','t','r','y','`',0 };
2248 if (!package)
2249 return ERROR_INVALID_HANDLE;
2251 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2252 if (rc != ERROR_SUCCESS)
2253 return ERROR_SUCCESS;
2255 /* increment progress bar each time action data is sent */
2256 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2258 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2260 msiobj_release(&view->hdr);
2261 return rc;
2264 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2266 package->script->CurrentlyScripting = TRUE;
2268 return ERROR_SUCCESS;
2272 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2274 MSICOMPONENT *comp;
2275 DWORD progress = 0;
2276 DWORD total = 0;
2277 static const WCHAR q1[]=
2278 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2279 '`','R','e','g','i','s','t','r','y','`',0};
2280 UINT rc;
2281 MSIQUERY * view;
2282 MSIFEATURE *feature;
2283 MSIFILE *file;
2285 TRACE("InstallValidate\n");
2287 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2288 if (rc == ERROR_SUCCESS)
2290 MSI_IterateRecords( view, &progress, NULL, package );
2291 msiobj_release( &view->hdr );
2292 total += progress * REG_PROGRESS_VALUE;
2295 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2296 total += COMPONENT_PROGRESS_VALUE;
2298 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2299 total += file->FileSize;
2301 ui_progress(package,0,total,0,0);
2303 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2305 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2306 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2307 feature->ActionRequest);
2310 return ERROR_SUCCESS;
2313 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2315 MSIPACKAGE* package = (MSIPACKAGE*)param;
2316 LPCWSTR cond = NULL;
2317 LPCWSTR message = NULL;
2318 static const WCHAR title[]=
2319 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2321 cond = MSI_RecordGetString(row,1);
2323 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2325 LPWSTR deformated;
2326 message = MSI_RecordGetString(row,2);
2327 deformat_string(package,message,&deformated);
2328 MessageBoxW(NULL,deformated,title,MB_OK);
2329 msi_free(deformated);
2330 return ERROR_FUNCTION_FAILED;
2333 return ERROR_SUCCESS;
2336 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2338 UINT rc;
2339 MSIQUERY * view = NULL;
2340 static const WCHAR ExecSeqQuery[] =
2341 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2342 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2344 TRACE("Checking launch conditions\n");
2346 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2347 if (rc != ERROR_SUCCESS)
2348 return ERROR_SUCCESS;
2350 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2351 msiobj_release(&view->hdr);
2353 return rc;
2356 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2359 if (!cmp->KeyPath)
2360 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2362 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2364 MSIRECORD * row = 0;
2365 UINT root,len;
2366 LPWSTR deformated,buffer,deformated_name;
2367 LPCWSTR key,name;
2368 static const WCHAR ExecSeqQuery[] =
2369 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2370 '`','R','e','g','i','s','t','r','y','`',' ',
2371 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2372 ' ','=',' ' ,'\'','%','s','\'',0 };
2373 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2374 static const WCHAR fmt2[]=
2375 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2377 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2378 if (!row)
2379 return NULL;
2381 root = MSI_RecordGetInteger(row,2);
2382 key = MSI_RecordGetString(row, 3);
2383 name = MSI_RecordGetString(row, 4);
2384 deformat_string(package, key , &deformated);
2385 deformat_string(package, name, &deformated_name);
2387 len = strlenW(deformated) + 6;
2388 if (deformated_name)
2389 len+=strlenW(deformated_name);
2391 buffer = msi_alloc( len *sizeof(WCHAR));
2393 if (deformated_name)
2394 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2395 else
2396 sprintfW(buffer,fmt,root,deformated);
2398 msi_free(deformated);
2399 msi_free(deformated_name);
2400 msiobj_release(&row->hdr);
2402 return buffer;
2404 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2406 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2407 return NULL;
2409 else
2411 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2413 if (file)
2414 return strdupW( file->TargetPath );
2416 return NULL;
2419 static HKEY openSharedDLLsKey(void)
2421 HKEY hkey=0;
2422 static const WCHAR path[] =
2423 {'S','o','f','t','w','a','r','e','\\',
2424 'M','i','c','r','o','s','o','f','t','\\',
2425 'W','i','n','d','o','w','s','\\',
2426 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2427 'S','h','a','r','e','d','D','L','L','s',0};
2429 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2430 return hkey;
2433 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2435 HKEY hkey;
2436 DWORD count=0;
2437 DWORD type;
2438 DWORD sz = sizeof(count);
2439 DWORD rc;
2441 hkey = openSharedDLLsKey();
2442 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2443 if (rc != ERROR_SUCCESS)
2444 count = 0;
2445 RegCloseKey(hkey);
2446 return count;
2449 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2451 HKEY hkey;
2453 hkey = openSharedDLLsKey();
2454 if (count > 0)
2455 msi_reg_set_val_dword( hkey, path, count );
2456 else
2457 RegDeleteValueW(hkey,path);
2458 RegCloseKey(hkey);
2459 return count;
2463 * Return TRUE if the count should be written out and FALSE if not
2465 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2467 MSIFEATURE *feature;
2468 INT count = 0;
2469 BOOL write = FALSE;
2471 /* only refcount DLLs */
2472 if (comp->KeyPath == NULL ||
2473 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2474 comp->Attributes & msidbComponentAttributesODBCDataSource)
2475 write = FALSE;
2476 else
2478 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2479 write = (count > 0);
2481 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2482 write = TRUE;
2485 /* increment counts */
2486 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2488 ComponentList *cl;
2490 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2491 continue;
2493 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2495 if ( cl->component == comp )
2496 count++;
2500 /* decrement counts */
2501 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2503 ComponentList *cl;
2505 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2506 continue;
2508 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2510 if ( cl->component == comp )
2511 count--;
2515 /* ref count all the files in the component */
2516 if (write)
2518 MSIFILE *file;
2520 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2522 if (file->Component == comp)
2523 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2527 /* add a count for permenent */
2528 if (comp->Attributes & msidbComponentAttributesPermanent)
2529 count ++;
2531 comp->RefCount = count;
2533 if (write)
2534 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2538 * Ok further analysis makes me think that this work is
2539 * actually done in the PublishComponents and PublishFeatures
2540 * step, and not here. It appears like the keypath and all that is
2541 * resolved in this step, however actually written in the Publish steps.
2542 * But we will leave it here for now because it is unclear
2544 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2546 WCHAR squished_pc[GUID_SIZE];
2547 WCHAR squished_cc[GUID_SIZE];
2548 UINT rc;
2549 MSICOMPONENT *comp;
2550 HKEY hkey=0,hkey2=0;
2552 /* writes the Component and Features values to the registry */
2554 rc = MSIREG_OpenComponents(&hkey);
2555 if (rc != ERROR_SUCCESS)
2556 return rc;
2558 squash_guid(package->ProductCode,squished_pc);
2559 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2561 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2563 MSIRECORD * uirow;
2565 ui_progress(package,2,0,0,0);
2566 if (!comp->ComponentId)
2567 continue;
2569 squash_guid(comp->ComponentId,squished_cc);
2571 msi_free(comp->FullKeypath);
2572 comp->FullKeypath = resolve_keypath( package, comp );
2574 /* do the refcounting */
2575 ACTION_RefCountComponent( package, comp );
2577 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2578 debugstr_w(comp->Component),
2579 debugstr_w(squished_cc),
2580 debugstr_w(comp->FullKeypath),
2581 comp->RefCount);
2583 * Write the keypath out if the component is to be registered
2584 * and delete the key if the component is to be deregistered
2586 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2588 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2589 if (rc != ERROR_SUCCESS)
2590 continue;
2592 if (!comp->FullKeypath)
2593 continue;
2595 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2597 if (comp->Attributes & msidbComponentAttributesPermanent)
2599 static const WCHAR szPermKey[] =
2600 { '0','0','0','0','0','0','0','0','0','0','0','0',
2601 '0','0','0','0','0','0','0','0','0','0','0','0',
2602 '0','0','0','0','0','0','0','0',0 };
2604 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2607 RegCloseKey(hkey2);
2609 /* UI stuff */
2610 uirow = MSI_CreateRecord(3);
2611 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2612 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2613 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2614 ui_actiondata(package,szProcessComponents,uirow);
2615 msiobj_release( &uirow->hdr );
2617 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2619 DWORD res;
2621 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2622 if (rc != ERROR_SUCCESS)
2623 continue;
2625 RegDeleteValueW(hkey2,squished_pc);
2627 /* if the key is empty delete it */
2628 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2629 RegCloseKey(hkey2);
2630 if (res == ERROR_NO_MORE_ITEMS)
2631 RegDeleteKeyW(hkey,squished_cc);
2633 /* UI stuff */
2634 uirow = MSI_CreateRecord(2);
2635 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2636 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2637 ui_actiondata(package,szProcessComponents,uirow);
2638 msiobj_release( &uirow->hdr );
2641 RegCloseKey(hkey);
2642 return rc;
2645 typedef struct {
2646 CLSID clsid;
2647 LPWSTR source;
2649 LPWSTR path;
2650 ITypeLib *ptLib;
2651 } typelib_struct;
2653 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2654 LPWSTR lpszName, LONG_PTR lParam)
2656 TLIBATTR *attr;
2657 typelib_struct *tl_struct = (typelib_struct*) lParam;
2658 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2659 int sz;
2660 HRESULT res;
2662 if (!IS_INTRESOURCE(lpszName))
2664 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2665 return TRUE;
2668 sz = strlenW(tl_struct->source)+4;
2669 sz *= sizeof(WCHAR);
2671 if ((INT)lpszName == 1)
2672 tl_struct->path = strdupW(tl_struct->source);
2673 else
2675 tl_struct->path = msi_alloc(sz);
2676 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2679 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2680 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2681 if (!SUCCEEDED(res))
2683 msi_free(tl_struct->path);
2684 tl_struct->path = NULL;
2686 return TRUE;
2689 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2690 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2692 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2693 return FALSE;
2696 msi_free(tl_struct->path);
2697 tl_struct->path = NULL;
2699 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2700 ITypeLib_Release(tl_struct->ptLib);
2702 return TRUE;
2705 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2707 MSIPACKAGE* package = (MSIPACKAGE*)param;
2708 LPCWSTR component;
2709 MSICOMPONENT *comp;
2710 MSIFILE *file;
2711 typelib_struct tl_struct;
2712 HMODULE module;
2713 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2715 component = MSI_RecordGetString(row,3);
2716 comp = get_loaded_component(package,component);
2717 if (!comp)
2718 return ERROR_SUCCESS;
2720 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2722 TRACE("Skipping typelib reg due to disabled component\n");
2724 comp->Action = comp->Installed;
2726 return ERROR_SUCCESS;
2729 comp->Action = INSTALLSTATE_LOCAL;
2731 file = get_loaded_file( package, comp->KeyPath );
2732 if (!file)
2733 return ERROR_SUCCESS;
2735 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2736 if (module)
2738 LPCWSTR guid;
2739 guid = MSI_RecordGetString(row,1);
2740 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2741 tl_struct.source = strdupW( file->TargetPath );
2742 tl_struct.path = NULL;
2744 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2745 (LONG_PTR)&tl_struct);
2747 if (tl_struct.path)
2749 LPWSTR help = NULL;
2750 LPCWSTR helpid;
2751 HRESULT res;
2753 helpid = MSI_RecordGetString(row,6);
2755 if (helpid)
2756 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2757 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2758 msi_free(help);
2760 if (!SUCCEEDED(res))
2761 ERR("Failed to register type library %s\n",
2762 debugstr_w(tl_struct.path));
2763 else
2765 ui_actiondata(package,szRegisterTypeLibraries,row);
2767 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2770 ITypeLib_Release(tl_struct.ptLib);
2771 msi_free(tl_struct.path);
2773 else
2774 ERR("Failed to load type library %s\n",
2775 debugstr_w(tl_struct.source));
2777 FreeLibrary(module);
2778 msi_free(tl_struct.source);
2780 else
2781 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2783 return ERROR_SUCCESS;
2786 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2789 * OK this is a bit confusing.. I am given a _Component key and I believe
2790 * that the file that is being registered as a type library is the "key file
2791 * of that component" which I interpret to mean "The file in the KeyPath of
2792 * that component".
2794 UINT rc;
2795 MSIQUERY * view;
2796 static const WCHAR Query[] =
2797 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2798 '`','T','y','p','e','L','i','b','`',0};
2800 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2801 if (rc != ERROR_SUCCESS)
2802 return ERROR_SUCCESS;
2804 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2805 msiobj_release(&view->hdr);
2806 return rc;
2809 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2811 MSIPACKAGE *package = (MSIPACKAGE*)param;
2812 LPWSTR target_file, target_folder, filename;
2813 LPCWSTR buffer, extension;
2814 MSICOMPONENT *comp;
2815 static const WCHAR szlnk[]={'.','l','n','k',0};
2816 IShellLinkW *sl;
2817 IPersistFile *pf;
2818 HRESULT res;
2820 buffer = MSI_RecordGetString(row,4);
2821 comp = get_loaded_component(package,buffer);
2822 if (!comp)
2823 return ERROR_SUCCESS;
2825 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2827 TRACE("Skipping shortcut creation due to disabled component\n");
2829 comp->Action = comp->Installed;
2831 return ERROR_SUCCESS;
2834 comp->Action = INSTALLSTATE_LOCAL;
2836 ui_actiondata(package,szCreateShortcuts,row);
2838 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2839 &IID_IShellLinkW, (LPVOID *) &sl );
2841 if (FAILED(res))
2843 ERR("Is IID_IShellLink\n");
2844 return ERROR_SUCCESS;
2847 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2848 if( FAILED( res ) )
2850 ERR("Is IID_IPersistFile\n");
2851 return ERROR_SUCCESS;
2854 buffer = MSI_RecordGetString(row,2);
2855 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2857 /* may be needed because of a bug somehwere else */
2858 create_full_pathW(target_folder);
2860 filename = msi_dup_record_field( row, 3 );
2861 reduce_to_longfilename(filename);
2863 extension = strchrW(filename,'.');
2864 if (!extension || strcmpiW(extension,szlnk))
2866 int len = strlenW(filename);
2867 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2868 memcpy(filename + len, szlnk, sizeof(szlnk));
2870 target_file = build_directory_name(2, target_folder, filename);
2871 msi_free(target_folder);
2872 msi_free(filename);
2874 buffer = MSI_RecordGetString(row,5);
2875 if (strchrW(buffer,'['))
2877 LPWSTR deformated;
2878 deformat_string(package,buffer,&deformated);
2879 IShellLinkW_SetPath(sl,deformated);
2880 msi_free(deformated);
2882 else
2884 FIXME("poorly handled shortcut format, advertised shortcut\n");
2885 IShellLinkW_SetPath(sl,comp->FullKeypath);
2888 if (!MSI_RecordIsNull(row,6))
2890 LPWSTR deformated;
2891 buffer = MSI_RecordGetString(row,6);
2892 deformat_string(package,buffer,&deformated);
2893 IShellLinkW_SetArguments(sl,deformated);
2894 msi_free(deformated);
2897 if (!MSI_RecordIsNull(row,7))
2899 buffer = MSI_RecordGetString(row,7);
2900 IShellLinkW_SetDescription(sl,buffer);
2903 if (!MSI_RecordIsNull(row,8))
2904 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2906 if (!MSI_RecordIsNull(row,9))
2908 LPWSTR Path;
2909 INT index;
2911 buffer = MSI_RecordGetString(row,9);
2913 Path = build_icon_path(package,buffer);
2914 index = MSI_RecordGetInteger(row,10);
2916 IShellLinkW_SetIconLocation(sl,Path,index);
2917 msi_free(Path);
2920 if (!MSI_RecordIsNull(row,11))
2921 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2923 if (!MSI_RecordIsNull(row,12))
2925 LPWSTR Path;
2926 buffer = MSI_RecordGetString(row,12);
2927 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
2928 IShellLinkW_SetWorkingDirectory(sl,Path);
2929 msi_free(Path);
2932 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
2933 IPersistFile_Save(pf,target_file,FALSE);
2935 msi_free(target_file);
2937 IPersistFile_Release( pf );
2938 IShellLinkW_Release( sl );
2940 return ERROR_SUCCESS;
2943 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
2945 UINT rc;
2946 HRESULT res;
2947 MSIQUERY * view;
2948 static const WCHAR Query[] =
2949 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2950 '`','S','h','o','r','t','c','u','t','`',0};
2952 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2953 if (rc != ERROR_SUCCESS)
2954 return ERROR_SUCCESS;
2956 res = CoInitialize( NULL );
2957 if (FAILED (res))
2959 ERR("CoInitialize failed\n");
2960 return ERROR_FUNCTION_FAILED;
2963 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
2964 msiobj_release(&view->hdr);
2966 CoUninitialize();
2968 return rc;
2971 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
2973 MSIPACKAGE* package = (MSIPACKAGE*)param;
2974 HANDLE the_file;
2975 LPWSTR FilePath;
2976 LPCWSTR FileName;
2977 CHAR buffer[1024];
2978 DWORD sz;
2979 UINT rc;
2980 MSIRECORD *uirow;
2982 FileName = MSI_RecordGetString(row,1);
2983 if (!FileName)
2985 ERR("Unable to get FileName\n");
2986 return ERROR_SUCCESS;
2989 FilePath = build_icon_path(package,FileName);
2991 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
2993 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2994 FILE_ATTRIBUTE_NORMAL, NULL);
2996 if (the_file == INVALID_HANDLE_VALUE)
2998 ERR("Unable to create file %s\n",debugstr_w(FilePath));
2999 msi_free(FilePath);
3000 return ERROR_SUCCESS;
3005 DWORD write;
3006 sz = 1024;
3007 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3008 if (rc != ERROR_SUCCESS)
3010 ERR("Failed to get stream\n");
3011 CloseHandle(the_file);
3012 DeleteFileW(FilePath);
3013 break;
3015 WriteFile(the_file,buffer,sz,&write,NULL);
3016 } while (sz == 1024);
3018 msi_free(FilePath);
3020 CloseHandle(the_file);
3022 uirow = MSI_CreateRecord(1);
3023 MSI_RecordSetStringW(uirow,1,FileName);
3024 ui_actiondata(package,szPublishProduct,uirow);
3025 msiobj_release( &uirow->hdr );
3027 return ERROR_SUCCESS;
3031 * 99% of the work done here is only done for
3032 * advertised installs. However this is where the
3033 * Icon table is processed and written out
3034 * so that is what I am going to do here.
3036 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3038 UINT rc;
3039 MSIQUERY * view;
3040 static const WCHAR Query[]=
3041 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3042 '`','I','c','o','n','`',0};
3043 /* for registry stuff */
3044 HKEY hkey=0;
3045 HKEY hukey=0;
3046 static const WCHAR szProductLanguage[] =
3047 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3048 static const WCHAR szARPProductIcon[] =
3049 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3050 static const WCHAR szProductVersion[] =
3051 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3052 DWORD langid;
3053 LPWSTR buffer;
3054 DWORD size;
3055 MSIHANDLE hDb, hSumInfo;
3057 /* write out icon files */
3059 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3060 if (rc == ERROR_SUCCESS)
3062 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3063 msiobj_release(&view->hdr);
3066 /* ok there is a lot more done here but i need to figure out what */
3068 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3069 if (rc != ERROR_SUCCESS)
3070 goto end;
3072 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3073 if (rc != ERROR_SUCCESS)
3074 goto end;
3077 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3078 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3079 msi_free(buffer);
3081 langid = msi_get_property_int( package, szProductLanguage, 0 );
3082 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3084 buffer = msi_dup_property( package, szARPProductIcon );
3085 if (buffer)
3087 LPWSTR path = build_icon_path(package,buffer);
3088 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3089 msi_free( path );
3091 msi_free(buffer);
3093 buffer = msi_dup_property( package, szProductVersion );
3094 if (buffer)
3096 DWORD verdword = build_version_dword(buffer);
3097 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3099 msi_free(buffer);
3101 /* FIXME: Need to write more keys to the user registry */
3103 hDb= alloc_msihandle( &package->db->hdr );
3104 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3105 MsiCloseHandle(hDb);
3106 if (rc == ERROR_SUCCESS)
3108 WCHAR guidbuffer[0x200];
3109 size = 0x200;
3110 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3111 guidbuffer, &size);
3112 if (rc == ERROR_SUCCESS)
3114 WCHAR squashed[GUID_SIZE];
3115 /* for now we only care about the first guid */
3116 LPWSTR ptr = strchrW(guidbuffer,';');
3117 if (ptr) *ptr = 0;
3118 squash_guid(guidbuffer,squashed);
3119 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3121 else
3123 ERR("Unable to query Revision_Number...\n");
3124 rc = ERROR_SUCCESS;
3126 MsiCloseHandle(hSumInfo);
3128 else
3130 ERR("Unable to open Summary Information\n");
3131 rc = ERROR_SUCCESS;
3134 end:
3136 RegCloseKey(hkey);
3137 RegCloseKey(hukey);
3139 return rc;
3142 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3144 MSIPACKAGE *package = (MSIPACKAGE*)param;
3145 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3146 LPWSTR deformated_section, deformated_key, deformated_value;
3147 LPWSTR folder, fullname = NULL;
3148 MSIRECORD * uirow;
3149 INT action;
3150 MSICOMPONENT *comp;
3151 static const WCHAR szWindowsFolder[] =
3152 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3154 component = MSI_RecordGetString(row, 8);
3155 comp = get_loaded_component(package,component);
3157 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3159 TRACE("Skipping ini file due to disabled component %s\n",
3160 debugstr_w(component));
3162 comp->Action = comp->Installed;
3164 return ERROR_SUCCESS;
3167 comp->Action = INSTALLSTATE_LOCAL;
3169 identifier = MSI_RecordGetString(row,1);
3170 filename = MSI_RecordGetString(row,2);
3171 dirproperty = MSI_RecordGetString(row,3);
3172 section = MSI_RecordGetString(row,4);
3173 key = MSI_RecordGetString(row,5);
3174 value = MSI_RecordGetString(row,6);
3175 action = MSI_RecordGetInteger(row,7);
3177 deformat_string(package,section,&deformated_section);
3178 deformat_string(package,key,&deformated_key);
3179 deformat_string(package,value,&deformated_value);
3181 if (dirproperty)
3183 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3184 if (!folder)
3185 folder = msi_dup_property( package, dirproperty );
3187 else
3188 folder = msi_dup_property( package, szWindowsFolder );
3190 if (!folder)
3192 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3193 goto cleanup;
3196 fullname = build_directory_name(2, folder, filename);
3198 if (action == 0)
3200 TRACE("Adding value %s to section %s in %s\n",
3201 debugstr_w(deformated_key), debugstr_w(deformated_section),
3202 debugstr_w(fullname));
3203 WritePrivateProfileStringW(deformated_section, deformated_key,
3204 deformated_value, fullname);
3206 else if (action == 1)
3208 WCHAR returned[10];
3209 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3210 returned, 10, fullname);
3211 if (returned[0] == 0)
3213 TRACE("Adding value %s to section %s in %s\n",
3214 debugstr_w(deformated_key), debugstr_w(deformated_section),
3215 debugstr_w(fullname));
3217 WritePrivateProfileStringW(deformated_section, deformated_key,
3218 deformated_value, fullname);
3221 else if (action == 3)
3222 FIXME("Append to existing section not yet implemented\n");
3224 uirow = MSI_CreateRecord(4);
3225 MSI_RecordSetStringW(uirow,1,identifier);
3226 MSI_RecordSetStringW(uirow,2,deformated_section);
3227 MSI_RecordSetStringW(uirow,3,deformated_key);
3228 MSI_RecordSetStringW(uirow,4,deformated_value);
3229 ui_actiondata(package,szWriteIniValues,uirow);
3230 msiobj_release( &uirow->hdr );
3231 cleanup:
3232 msi_free(fullname);
3233 msi_free(folder);
3234 msi_free(deformated_key);
3235 msi_free(deformated_value);
3236 msi_free(deformated_section);
3237 return ERROR_SUCCESS;
3240 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3242 UINT rc;
3243 MSIQUERY * view;
3244 static const WCHAR ExecSeqQuery[] =
3245 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3246 '`','I','n','i','F','i','l','e','`',0};
3248 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3249 if (rc != ERROR_SUCCESS)
3251 TRACE("no IniFile table\n");
3252 return ERROR_SUCCESS;
3255 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3256 msiobj_release(&view->hdr);
3257 return rc;
3260 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3262 MSIPACKAGE *package = (MSIPACKAGE*)param;
3263 LPCWSTR filename;
3264 LPWSTR FullName;
3265 MSIFILE *file;
3266 DWORD len;
3267 static const WCHAR ExeStr[] =
3268 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3269 static const WCHAR close[] = {'\"',0};
3270 STARTUPINFOW si;
3271 PROCESS_INFORMATION info;
3272 BOOL brc;
3273 MSIRECORD *uirow;
3274 LPWSTR uipath, p;
3276 memset(&si,0,sizeof(STARTUPINFOW));
3278 filename = MSI_RecordGetString(row,1);
3279 file = get_loaded_file( package, filename );
3281 if (!file)
3283 ERR("Unable to find file id %s\n",debugstr_w(filename));
3284 return ERROR_SUCCESS;
3287 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3289 FullName = msi_alloc(len*sizeof(WCHAR));
3290 strcpyW(FullName,ExeStr);
3291 strcatW( FullName, file->TargetPath );
3292 strcatW(FullName,close);
3294 TRACE("Registering %s\n",debugstr_w(FullName));
3295 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3296 &si, &info);
3298 if (brc)
3299 msi_dialog_check_messages(info.hProcess);
3301 msi_free(FullName);
3303 /* the UI chunk */
3304 uirow = MSI_CreateRecord( 2 );
3305 uipath = strdupW( file->TargetPath );
3306 p = strrchrW(uipath,'\\');
3307 if (p)
3308 p[1]=0;
3309 MSI_RecordSetStringW( uirow, 1, &p[2] );
3310 MSI_RecordSetStringW( uirow, 2, uipath);
3311 ui_actiondata( package, szSelfRegModules, uirow);
3312 msiobj_release( &uirow->hdr );
3313 msi_free( uipath );
3314 /* FIXME: call ui_progress? */
3316 return ERROR_SUCCESS;
3319 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3321 UINT rc;
3322 MSIQUERY * view;
3323 static const WCHAR ExecSeqQuery[] =
3324 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3325 '`','S','e','l','f','R','e','g','`',0};
3327 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3328 if (rc != ERROR_SUCCESS)
3330 TRACE("no SelfReg table\n");
3331 return ERROR_SUCCESS;
3334 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3335 msiobj_release(&view->hdr);
3337 return ERROR_SUCCESS;
3340 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3342 MSIFEATURE *feature;
3343 UINT rc;
3344 HKEY hkey=0;
3345 HKEY hukey=0;
3347 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3348 if (rc != ERROR_SUCCESS)
3349 goto end;
3351 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3352 if (rc != ERROR_SUCCESS)
3353 goto end;
3355 /* here the guids are base 85 encoded */
3356 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3358 ComponentList *cl;
3359 LPWSTR data = NULL;
3360 GUID clsid;
3361 INT size;
3362 BOOL absent = FALSE;
3363 MSIRECORD *uirow;
3365 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3366 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3367 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3368 absent = TRUE;
3370 size = 1;
3371 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3373 size += 21;
3375 if (feature->Feature_Parent)
3376 size += strlenW( feature->Feature_Parent )+2;
3378 data = msi_alloc(size * sizeof(WCHAR));
3380 data[0] = 0;
3381 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3383 MSICOMPONENT* component = cl->component;
3384 WCHAR buf[21];
3386 memset(buf,0,sizeof(buf));
3387 if (component->ComponentId)
3389 TRACE("From %s\n",debugstr_w(component->ComponentId));
3390 CLSIDFromString(component->ComponentId, &clsid);
3391 encode_base85_guid(&clsid,buf);
3392 TRACE("to %s\n",debugstr_w(buf));
3393 strcatW(data,buf);
3396 if (feature->Feature_Parent)
3398 static const WCHAR sep[] = {'\2',0};
3399 strcatW(data,sep);
3400 strcatW(data,feature->Feature_Parent);
3403 msi_reg_set_val_str( hkey, feature->Feature, data );
3404 msi_free(data);
3406 size = 0;
3407 if (feature->Feature_Parent)
3408 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3409 if (!absent)
3411 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3412 (LPBYTE)feature->Feature_Parent,size);
3414 else
3416 size += 2*sizeof(WCHAR);
3417 data = msi_alloc(size);
3418 data[0] = 0x6;
3419 data[1] = 0;
3420 if (feature->Feature_Parent)
3421 strcpyW( &data[1], feature->Feature_Parent );
3422 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3423 (LPBYTE)data,size);
3424 msi_free(data);
3427 /* the UI chunk */
3428 uirow = MSI_CreateRecord( 1 );
3429 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3430 ui_actiondata( package, szPublishFeatures, uirow);
3431 msiobj_release( &uirow->hdr );
3432 /* FIXME: call ui_progress? */
3435 end:
3436 RegCloseKey(hkey);
3437 RegCloseKey(hukey);
3438 return rc;
3441 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3443 static const WCHAR installerPathFmt[] = {
3444 '%','s','\\','I','n','s','t','a','l','l','e','r','\\',0};
3445 static const WCHAR fmt[] = {
3446 '%','s','\\',
3447 'I','n','s','t','a','l','l','e','r','\\',
3448 '%','x','.','m','s','i',0};
3449 static const WCHAR szOriginalDatabase[] =
3450 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3451 WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
3452 INT num, start;
3453 LPWSTR msiFilePath;
3454 BOOL r;
3456 /* copy the package locally */
3457 num = GetTickCount() & 0xffff;
3458 if (!num)
3459 num = 1;
3460 start = num;
3461 GetWindowsDirectoryW( windir, MAX_PATH );
3462 snprintfW( packagefile, MAX_PATH, fmt, windir, num );
3465 HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
3466 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3467 if (handle != INVALID_HANDLE_VALUE)
3469 CloseHandle(handle);
3470 break;
3472 if (GetLastError() != ERROR_FILE_EXISTS &&
3473 GetLastError() != ERROR_SHARING_VIOLATION)
3474 break;
3475 if (!(++num & 0xffff)) num = 1;
3476 sprintfW(packagefile,fmt,num);
3477 } while (num != start);
3479 snprintfW( path, MAX_PATH, installerPathFmt, windir );
3480 create_full_pathW(path);
3482 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3484 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3485 r = CopyFileW( msiFilePath, packagefile, FALSE);
3486 msi_free( msiFilePath );
3488 if (!r)
3490 ERR("Unable to copy package (%s -> %s) (error %ld)\n",
3491 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3492 return ERROR_FUNCTION_FAILED;
3495 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3496 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3497 return ERROR_SUCCESS;
3500 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3502 LPWSTR prop, val, key;
3503 static const LPCSTR propval[] = {
3504 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3505 "ARPCONTACT", "Contact",
3506 "ARPCOMMENTS", "Comments",
3507 "ProductName", "DisplayName",
3508 "ProductVersion", "DisplayVersion",
3509 "ARPHELPLINK", "HelpLink",
3510 "ARPHELPTELEPHONE", "HelpTelephone",
3511 "ARPINSTALLLOCATION", "InstallLocation",
3512 "SourceDir", "InstallSource",
3513 "Manufacturer", "Publisher",
3514 "ARPREADME", "Readme",
3515 "ARPSIZE", "Size",
3516 "ARPURLINFOABOUT", "URLInfoAbout",
3517 "ARPURLUPDATEINFO", "URLUpdateInfo",
3518 NULL,
3520 const LPCSTR *p = propval;
3522 while( *p )
3524 prop = strdupAtoW( *p++ );
3525 key = strdupAtoW( *p++ );
3526 val = msi_dup_property( package, prop );
3527 msi_reg_set_val_str( hkey, key, val );
3528 msi_free(val);
3529 msi_free(key);
3530 msi_free(prop);
3532 return ERROR_SUCCESS;
3535 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3537 HKEY hkey=0;
3538 LPWSTR buffer = NULL;
3539 UINT rc;
3540 DWORD size, langid;
3541 static const WCHAR szWindowsInstaller[] =
3542 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3543 static const WCHAR szUpgradeCode[] =
3544 {'U','p','g','r','a','d','e','C','o','d','e',0};
3545 static const WCHAR modpath_fmt[] =
3546 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3547 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3548 static const WCHAR szModifyPath[] =
3549 {'M','o','d','i','f','y','P','a','t','h',0};
3550 static const WCHAR szUninstallString[] =
3551 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3552 static const WCHAR szEstimatedSize[] =
3553 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3554 static const WCHAR szProductLanguage[] =
3555 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3556 static const WCHAR szProductVersion[] =
3557 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3559 SYSTEMTIME systime;
3560 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3561 LPWSTR upgrade_code;
3562 WCHAR szDate[9];
3564 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3565 if (rc != ERROR_SUCCESS)
3566 return rc;
3568 /* dump all the info i can grab */
3569 /* FIXME: Flesh out more information */
3571 msi_write_uninstall_property_vals( package, hkey );
3573 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3575 msi_make_package_local( package, hkey );
3577 /* do ModifyPath and UninstallString */
3578 size = deformat_string(package,modpath_fmt,&buffer);
3579 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3580 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3581 msi_free(buffer);
3583 /* FIXME: Write real Estimated Size when we have it */
3584 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3586 GetLocalTime(&systime);
3587 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3588 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3590 langid = msi_get_property_int( package, szProductLanguage, 0 );
3591 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3593 buffer = msi_dup_property( package, szProductVersion );
3594 if (buffer)
3596 DWORD verdword = build_version_dword(buffer);
3598 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3599 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3600 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3602 msi_free(buffer);
3604 /* Handle Upgrade Codes */
3605 upgrade_code = msi_dup_property( package, szUpgradeCode );
3606 if (upgrade_code)
3608 HKEY hkey2;
3609 WCHAR squashed[33];
3610 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3611 squash_guid(package->ProductCode,squashed);
3612 msi_reg_set_val_str( hkey2, squashed, NULL );
3613 RegCloseKey(hkey2);
3614 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3615 squash_guid(package->ProductCode,squashed);
3616 msi_reg_set_val_str( hkey2, squashed, NULL );
3617 RegCloseKey(hkey2);
3619 msi_free(upgrade_code);
3622 RegCloseKey(hkey);
3624 /* FIXME: call ui_actiondata */
3626 return ERROR_SUCCESS;
3629 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3631 return execute_script(package,INSTALL_SCRIPT);
3634 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3636 UINT rc;
3638 /* turn off scheduleing */
3639 package->script->CurrentlyScripting= FALSE;
3641 /* first do the same as an InstallExecute */
3642 rc = ACTION_InstallExecute(package);
3643 if (rc != ERROR_SUCCESS)
3644 return rc;
3646 /* then handle Commit Actions */
3647 rc = execute_script(package,COMMIT_SCRIPT);
3649 return rc;
3652 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3654 static const WCHAR RunOnce[] = {
3655 'S','o','f','t','w','a','r','e','\\',
3656 'M','i','c','r','o','s','o','f','t','\\',
3657 'W','i','n','d','o','w','s','\\',
3658 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3659 'R','u','n','O','n','c','e',0};
3660 static const WCHAR InstallRunOnce[] = {
3661 'S','o','f','t','w','a','r','e','\\',
3662 'M','i','c','r','o','s','o','f','t','\\',
3663 'W','i','n','d','o','w','s','\\',
3664 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3665 'I','n','s','t','a','l','l','e','r','\\',
3666 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3668 static const WCHAR msiexec_fmt[] = {
3669 '%','s',
3670 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3671 '\"','%','s','\"',0};
3672 static const WCHAR install_fmt[] = {
3673 '/','I',' ','\"','%','s','\"',' ',
3674 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3675 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3676 WCHAR buffer[256], sysdir[MAX_PATH];
3677 HKEY hkey;
3678 WCHAR squished_pc[100];
3680 squash_guid(package->ProductCode,squished_pc);
3682 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3683 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3684 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3685 squished_pc);
3687 msi_reg_set_val_str( hkey, squished_pc, buffer );
3688 RegCloseKey(hkey);
3690 TRACE("Reboot command %s\n",debugstr_w(buffer));
3692 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3693 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3695 msi_reg_set_val_str( hkey, squished_pc, buffer );
3696 RegCloseKey(hkey);
3698 return ERROR_INSTALL_SUSPEND;
3701 UINT ACTION_ResolveSource(MSIPACKAGE* package)
3703 DWORD attrib;
3704 UINT rc;
3706 * we are currently doing what should be done here in the top level Install
3707 * however for Adminastrative and uninstalls this step will be needed
3709 if (!package->PackagePath)
3710 return ERROR_SUCCESS;
3712 attrib = GetFileAttributesW(package->PackagePath);
3713 if (attrib == INVALID_FILE_ATTRIBUTES)
3715 LPWSTR prompt;
3716 LPWSTR msg;
3717 DWORD size = 0;
3719 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3720 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3721 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3722 if (rc == ERROR_MORE_DATA)
3724 prompt = msi_alloc(size * sizeof(WCHAR));
3725 MsiSourceListGetInfoW(package->ProductCode, NULL,
3726 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3727 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3729 else
3730 prompt = strdupW(package->PackagePath);
3732 msg = generate_error_string(package,1302,1,prompt);
3733 while(attrib == INVALID_FILE_ATTRIBUTES)
3735 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3736 if (rc == IDCANCEL)
3738 rc = ERROR_INSTALL_USEREXIT;
3739 break;
3741 attrib = GetFileAttributesW(package->PackagePath);
3743 msi_free(prompt);
3744 rc = ERROR_SUCCESS;
3746 else
3747 return ERROR_SUCCESS;
3749 return rc;
3752 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3754 HKEY hkey=0;
3755 LPWSTR buffer;
3756 LPWSTR productid;
3757 UINT rc,i;
3759 static const WCHAR szPropKeys[][80] =
3761 {'P','r','o','d','u','c','t','I','D',0},
3762 {'U','S','E','R','N','A','M','E',0},
3763 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3764 {0},
3767 static const WCHAR szRegKeys[][80] =
3769 {'P','r','o','d','u','c','t','I','D',0},
3770 {'R','e','g','O','w','n','e','r',0},
3771 {'R','e','g','C','o','m','p','a','n','y',0},
3772 {0},
3775 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3776 if (!productid)
3777 return ERROR_SUCCESS;
3779 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3780 if (rc != ERROR_SUCCESS)
3781 goto end;
3783 for( i = 0; szPropKeys[i][0]; i++ )
3785 buffer = msi_dup_property( package, szPropKeys[i] );
3786 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3787 msi_free( buffer );
3790 end:
3791 msi_free(productid);
3792 RegCloseKey(hkey);
3794 /* FIXME: call ui_actiondata */
3796 return ERROR_SUCCESS;
3800 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3802 UINT rc;
3804 package->script->InWhatSequence |= SEQUENCE_EXEC;
3805 rc = ACTION_ProcessExecSequence(package,FALSE);
3806 return rc;
3811 * Code based off of code located here
3812 * http://www.codeproject.com/gdi/fontnamefromfile.asp
3814 * Using string index 4 (full font name) instead of 1 (family name)
3816 static LPWSTR load_ttfname_from(LPCWSTR filename)
3818 HANDLE handle;
3819 LPWSTR ret = NULL;
3820 int i;
3822 typedef struct _tagTT_OFFSET_TABLE{
3823 USHORT uMajorVersion;
3824 USHORT uMinorVersion;
3825 USHORT uNumOfTables;
3826 USHORT uSearchRange;
3827 USHORT uEntrySelector;
3828 USHORT uRangeShift;
3829 }TT_OFFSET_TABLE;
3831 typedef struct _tagTT_TABLE_DIRECTORY{
3832 char szTag[4]; /* table name */
3833 ULONG uCheckSum; /* Check sum */
3834 ULONG uOffset; /* Offset from beginning of file */
3835 ULONG uLength; /* length of the table in bytes */
3836 }TT_TABLE_DIRECTORY;
3838 typedef struct _tagTT_NAME_TABLE_HEADER{
3839 USHORT uFSelector; /* format selector. Always 0 */
3840 USHORT uNRCount; /* Name Records count */
3841 USHORT uStorageOffset; /* Offset for strings storage,
3842 * from start of the table */
3843 }TT_NAME_TABLE_HEADER;
3845 typedef struct _tagTT_NAME_RECORD{
3846 USHORT uPlatformID;
3847 USHORT uEncodingID;
3848 USHORT uLanguageID;
3849 USHORT uNameID;
3850 USHORT uStringLength;
3851 USHORT uStringOffset; /* from start of storage area */
3852 }TT_NAME_RECORD;
3854 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
3855 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
3857 handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
3858 FILE_ATTRIBUTE_NORMAL, 0 );
3859 if (handle != INVALID_HANDLE_VALUE)
3861 TT_TABLE_DIRECTORY tblDir;
3862 BOOL bFound = FALSE;
3863 TT_OFFSET_TABLE ttOffsetTable;
3864 DWORD dwRead;
3866 ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL);
3867 ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
3868 ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
3869 ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
3871 if (ttOffsetTable.uMajorVersion != 1 ||
3872 ttOffsetTable.uMinorVersion != 0)
3873 return NULL;
3875 for (i=0; i< ttOffsetTable.uNumOfTables; i++)
3877 ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL);
3878 if (strncmp(tblDir.szTag,"name",4)==0)
3880 bFound = TRUE;
3881 tblDir.uLength = SWAPLONG(tblDir.uLength);
3882 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
3883 break;
3887 if (bFound)
3889 TT_NAME_TABLE_HEADER ttNTHeader;
3890 TT_NAME_RECORD ttRecord;
3892 SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
3893 ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
3894 &dwRead,NULL);
3896 ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
3897 ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
3898 bFound = FALSE;
3899 for(i=0; i<ttNTHeader.uNRCount; i++)
3901 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL);
3902 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
3903 /* 4 is the Full Font Name */
3904 if(ttRecord.uNameID == 4)
3906 int nPos;
3907 LPSTR buf;
3908 static LPCSTR tt = " (TrueType)";
3910 ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
3911 ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
3912 nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
3913 SetFilePointer(handle, tblDir.uOffset +
3914 ttRecord.uStringOffset +
3915 ttNTHeader.uStorageOffset,
3916 NULL, FILE_BEGIN);
3917 buf = msi_alloc( ttRecord.uStringLength + 1 + strlen(tt) );
3918 memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
3919 ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
3920 if (strlen(buf) > 0)
3922 strcat(buf,tt);
3923 ret = strdupAtoW(buf);
3924 msi_free(buf);
3925 break;
3928 msi_free(buf);
3929 SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
3933 CloseHandle(handle);
3935 else
3936 ERR("Unable to open font file %s\n", debugstr_w(filename));
3938 TRACE("Returning fontname %s\n",debugstr_w(ret));
3939 return ret;
3942 static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
3944 MSIPACKAGE *package = (MSIPACKAGE*)param;
3945 LPWSTR name;
3946 LPCWSTR filename;
3947 MSIFILE *file;
3948 static const WCHAR regfont1[] =
3949 {'S','o','f','t','w','a','r','e','\\',
3950 'M','i','c','r','o','s','o','f','t','\\',
3951 'W','i','n','d','o','w','s',' ','N','T','\\',
3952 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3953 'F','o','n','t','s',0};
3954 static const WCHAR regfont2[] =
3955 {'S','o','f','t','w','a','r','e','\\',
3956 'M','i','c','r','o','s','o','f','t','\\',
3957 'W','i','n','d','o','w','s','\\',
3958 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3959 'F','o','n','t','s',0};
3960 HKEY hkey1;
3961 HKEY hkey2;
3962 MSIRECORD *uirow;
3963 LPWSTR uipath, p;
3965 filename = MSI_RecordGetString( row, 1 );
3966 file = get_loaded_file( package, filename );
3967 if (!file)
3969 ERR("Unable to load file\n");
3970 return ERROR_SUCCESS;
3973 /* check to make sure that component is installed */
3974 if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
3976 TRACE("Skipping: Component not scheduled for install\n");
3977 return ERROR_SUCCESS;
3980 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
3981 RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
3983 if (MSI_RecordIsNull(row,2))
3984 name = load_ttfname_from( file->TargetPath );
3985 else
3986 name = msi_dup_record_field(row,2);
3988 if (name)
3990 msi_reg_set_val_str( hkey1, name, file->FileName );
3991 msi_reg_set_val_str( hkey2, name, file->FileName );
3994 msi_free(name);
3995 RegCloseKey(hkey1);
3996 RegCloseKey(hkey2);
3998 /* the UI chunk */
3999 uirow = MSI_CreateRecord( 1 );
4000 uipath = strdupW( file->TargetPath );
4001 p = strrchrW(uipath,'\\');
4002 if (p) p++;
4003 else p = uipath;
4004 MSI_RecordSetStringW( uirow, 1, p );
4005 ui_actiondata( package, szRegisterFonts, uirow);
4006 msiobj_release( &uirow->hdr );
4007 msi_free( uipath );
4008 /* FIXME: call ui_progress? */
4010 return ERROR_SUCCESS;
4013 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
4015 UINT rc;
4016 MSIQUERY * view;
4017 static const WCHAR ExecSeqQuery[] =
4018 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4019 '`','F','o','n','t','`',0};
4021 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4022 if (rc != ERROR_SUCCESS)
4024 TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
4025 return ERROR_SUCCESS;
4028 MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
4029 msiobj_release(&view->hdr);
4031 return ERROR_SUCCESS;
4034 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4036 MSIPACKAGE *package = (MSIPACKAGE*)param;
4037 LPCWSTR compgroupid=NULL;
4038 LPCWSTR feature=NULL;
4039 LPCWSTR text = NULL;
4040 LPCWSTR qualifier = NULL;
4041 LPCWSTR component = NULL;
4042 LPWSTR advertise = NULL;
4043 LPWSTR output = NULL;
4044 HKEY hkey;
4045 UINT rc = ERROR_SUCCESS;
4046 MSICOMPONENT *comp;
4047 DWORD sz = 0;
4048 MSIRECORD *uirow;
4050 component = MSI_RecordGetString(rec,3);
4051 comp = get_loaded_component(package,component);
4053 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4054 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4055 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4057 TRACE("Skipping: Component %s not scheduled for install\n",
4058 debugstr_w(component));
4060 return ERROR_SUCCESS;
4063 compgroupid = MSI_RecordGetString(rec,1);
4064 qualifier = MSI_RecordGetString(rec,2);
4066 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4067 if (rc != ERROR_SUCCESS)
4068 goto end;
4070 text = MSI_RecordGetString(rec,4);
4071 feature = MSI_RecordGetString(rec,5);
4073 advertise = create_component_advertise_string(package, comp, feature);
4075 sz = strlenW(advertise);
4077 if (text)
4078 sz += lstrlenW(text);
4080 sz+=3;
4081 sz *= sizeof(WCHAR);
4083 output = msi_alloc(sz);
4084 memset(output,0,sz);
4085 strcpyW(output,advertise);
4086 msi_free(advertise);
4088 if (text)
4089 strcatW(output,text);
4091 msi_reg_set_val_multi_str( hkey, qualifier, output );
4093 end:
4094 RegCloseKey(hkey);
4095 msi_free(output);
4097 /* the UI chunk */
4098 uirow = MSI_CreateRecord( 2 );
4099 MSI_RecordSetStringW( uirow, 1, compgroupid );
4100 MSI_RecordSetStringW( uirow, 2, qualifier);
4101 ui_actiondata( package, szPublishComponents, uirow);
4102 msiobj_release( &uirow->hdr );
4103 /* FIXME: call ui_progress? */
4105 return rc;
4109 * At present I am ignorning the advertised components part of this and only
4110 * focusing on the qualified component sets
4112 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4114 UINT rc;
4115 MSIQUERY * view;
4116 static const WCHAR ExecSeqQuery[] =
4117 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4118 '`','P','u','b','l','i','s','h',
4119 'C','o','m','p','o','n','e','n','t','`',0};
4121 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4122 if (rc != ERROR_SUCCESS)
4123 return ERROR_SUCCESS;
4125 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4126 msiobj_release(&view->hdr);
4128 return rc;
4131 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4132 LPCSTR action, LPCWSTR table )
4134 static const WCHAR query[] = {
4135 'S','E','L','E','C','T',' ','*',' ',
4136 'F','R','O','M',' ','`','%','s','`',0 };
4137 MSIQUERY *view = NULL;
4138 DWORD count = 0;
4139 UINT r;
4141 r = MSI_OpenQuery( package->db, &view, query, table );
4142 if (r == ERROR_SUCCESS)
4144 r = MSI_IterateRecords(view, &count, NULL, package);
4145 msiobj_release(&view->hdr);
4148 if (count)
4149 FIXME("%s -> %lu ignored %s table values\n",
4150 action, count, debugstr_w(table));
4152 return ERROR_SUCCESS;
4155 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4157 TRACE("%p\n", package);
4158 return ERROR_SUCCESS;
4161 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4163 static const WCHAR table[] =
4164 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4165 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4168 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4170 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4171 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4174 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4176 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4177 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4180 static UINT ACTION_BindImage( MSIPACKAGE *package )
4182 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4183 return msi_unimplemented_action_stub( package, "BindImage", table );
4186 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4188 static const WCHAR table[] = {
4189 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4190 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4193 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4195 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4196 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4199 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4201 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4202 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4205 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4207 static const WCHAR table[] = {
4208 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0 };
4209 return msi_unimplemented_action_stub( package, "InstallServices", table );
4212 static UINT ACTION_StartServices( MSIPACKAGE *package )
4214 static const WCHAR table[] = {
4215 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4216 return msi_unimplemented_action_stub( package, "StartServices", table );
4219 static UINT ACTION_StopServices( MSIPACKAGE *package )
4221 static const WCHAR table[] = {
4222 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4223 return msi_unimplemented_action_stub( package, "StopServices", table );
4226 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4228 static const WCHAR table[] = {
4229 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4230 return msi_unimplemented_action_stub( package, "DeleteServices", table );
4233 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4235 static const WCHAR table[] = {
4236 'E','n','v','i','r','o','n','m','e','n','t',0 };
4237 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4240 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4242 static const WCHAR table[] = {
4243 'E','n','v','i','r','o','n','m','e','n','t',0 };
4244 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4247 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4249 static const WCHAR table[] = {
4250 'M','s','i','A','s','s','e','m','b','l','y',0 };
4251 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4254 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4256 static const WCHAR table[] = {
4257 'M','s','i','A','s','s','e','m','b','l','y',0 };
4258 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4261 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4263 static const WCHAR table[] = { 'F','o','n','t',0 };
4264 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4267 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4269 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4270 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4273 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4275 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4276 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4279 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4281 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4282 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4285 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4287 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4288 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4291 static struct _actions StandardActions[] = {
4292 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4293 { szAppSearch, ACTION_AppSearch },
4294 { szBindImage, ACTION_BindImage },
4295 { szCCPSearch, ACTION_CCPSearch},
4296 { szCostFinalize, ACTION_CostFinalize },
4297 { szCostInitialize, ACTION_CostInitialize },
4298 { szCreateFolders, ACTION_CreateFolders },
4299 { szCreateShortcuts, ACTION_CreateShortcuts },
4300 { szDeleteServices, ACTION_DeleteServices },
4301 { szDisableRollback, NULL},
4302 { szDuplicateFiles, ACTION_DuplicateFiles },
4303 { szExecuteAction, ACTION_ExecuteAction },
4304 { szFileCost, ACTION_FileCost },
4305 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4306 { szForceReboot, ACTION_ForceReboot },
4307 { szInstallAdminPackage, NULL},
4308 { szInstallExecute, ACTION_InstallExecute },
4309 { szInstallExecuteAgain, ACTION_InstallExecute },
4310 { szInstallFiles, ACTION_InstallFiles},
4311 { szInstallFinalize, ACTION_InstallFinalize },
4312 { szInstallInitialize, ACTION_InstallInitialize },
4313 { szInstallSFPCatalogFile, NULL},
4314 { szInstallValidate, ACTION_InstallValidate },
4315 { szIsolateComponents, ACTION_IsolateComponents },
4316 { szLaunchConditions, ACTION_LaunchConditions },
4317 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4318 { szMoveFiles, ACTION_MoveFiles },
4319 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4320 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4321 { szInstallODBC, NULL},
4322 { szInstallServices, ACTION_InstallServices },
4323 { szPatchFiles, ACTION_PatchFiles },
4324 { szProcessComponents, ACTION_ProcessComponents },
4325 { szPublishComponents, ACTION_PublishComponents },
4326 { szPublishFeatures, ACTION_PublishFeatures },
4327 { szPublishProduct, ACTION_PublishProduct },
4328 { szRegisterClassInfo, ACTION_RegisterClassInfo },
4329 { szRegisterComPlus, ACTION_RegisterComPlus},
4330 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4331 { szRegisterFonts, ACTION_RegisterFonts },
4332 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4333 { szRegisterProduct, ACTION_RegisterProduct },
4334 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4335 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4336 { szRegisterUser, ACTION_RegisterUser},
4337 { szRemoveDuplicateFiles, NULL},
4338 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4339 { szRemoveExistingProducts, NULL},
4340 { szRemoveFiles, ACTION_RemoveFiles},
4341 { szRemoveFolders, NULL},
4342 { szRemoveIniValues, ACTION_RemoveIniValues },
4343 { szRemoveODBC, NULL},
4344 { szRemoveRegistryValues, NULL},
4345 { szRemoveShortcuts, NULL},
4346 { szResolveSource, ACTION_ResolveSource},
4347 { szRMCCPSearch, ACTION_RMCCPSearch},
4348 { szScheduleReboot, NULL},
4349 { szSelfRegModules, ACTION_SelfRegModules },
4350 { szSelfUnregModules, ACTION_SelfUnregModules },
4351 { szSetODBCFolders, NULL},
4352 { szStartServices, ACTION_StartServices },
4353 { szStopServices, ACTION_StopServices },
4354 { szUnpublishComponents, NULL},
4355 { szUnpublishFeatures, NULL},
4356 { szUnregisterClassInfo, NULL},
4357 { szUnregisterComPlus, ACTION_UnregisterComPlus},
4358 { szUnregisterExtensionInfo, NULL},
4359 { szUnregisterFonts, ACTION_UnregisterFonts },
4360 { szUnregisterMIMEInfo, NULL},
4361 { szUnregisterProgIdInfo, NULL},
4362 { szUnregisterTypeLibraries, NULL},
4363 { szValidateProductID, NULL},
4364 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4365 { szWriteIniValues, ACTION_WriteIniValues },
4366 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4367 { NULL, NULL},