wined3d: Add missing check for p8 primary in surface_download_data.
[wine.git] / dlls / msi / action.c
blobd7acc127f6e4cf444e5b7d58f68f24b637b01c11
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "msipriv.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "wine/unicode.h"
37 #include "winver.h"
39 #define REG_PROGRESS_VALUE 13200
40 #define COMPONENT_PROGRESS_VALUE 24000
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
45 * Prototypes
47 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
48 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
49 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
50 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
53 * consts and values used
55 static const WCHAR c_colon[] = {'C',':','\\',0};
57 static const WCHAR szCreateFolders[] =
58 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
59 static const WCHAR szCostFinalize[] =
60 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
61 const WCHAR szInstallFiles[] =
62 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
63 const WCHAR szDuplicateFiles[] =
64 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
65 static const WCHAR szWriteRegistryValues[] =
66 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
67 'V','a','l','u','e','s',0};
68 static const WCHAR szCostInitialize[] =
69 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
70 static const WCHAR szFileCost[] =
71 {'F','i','l','e','C','o','s','t',0};
72 static const WCHAR szInstallInitialize[] =
73 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
74 static const WCHAR szInstallValidate[] =
75 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
76 static const WCHAR szLaunchConditions[] =
77 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
78 static const WCHAR szProcessComponents[] =
79 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
80 static const WCHAR szRegisterTypeLibraries[] =
81 {'R','e','g','i','s','t','e','r','T','y','p','e',
82 'L','i','b','r','a','r','i','e','s',0};
83 const WCHAR szRegisterClassInfo[] =
84 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
85 const WCHAR szRegisterProgIdInfo[] =
86 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
87 static const WCHAR szCreateShortcuts[] =
88 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
89 static const WCHAR szPublishProduct[] =
90 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
91 static const WCHAR szWriteIniValues[] =
92 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
93 static const WCHAR szSelfRegModules[] =
94 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
95 static const WCHAR szPublishFeatures[] =
96 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
97 static const WCHAR szRegisterProduct[] =
98 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
99 static const WCHAR szInstallExecute[] =
100 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
101 static const WCHAR szInstallExecuteAgain[] =
102 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
103 'A','g','a','i','n',0};
104 static const WCHAR szInstallFinalize[] =
105 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
106 static const WCHAR szForceReboot[] =
107 {'F','o','r','c','e','R','e','b','o','o','t',0};
108 static const WCHAR szResolveSource[] =
109 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
110 static const WCHAR szAppSearch[] =
111 {'A','p','p','S','e','a','r','c','h',0};
112 static const WCHAR szAllocateRegistrySpace[] =
113 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
114 'S','p','a','c','e',0};
115 static const WCHAR szBindImage[] =
116 {'B','i','n','d','I','m','a','g','e',0};
117 static const WCHAR szCCPSearch[] =
118 {'C','C','P','S','e','a','r','c','h',0};
119 static const WCHAR szDeleteServices[] =
120 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
121 static const WCHAR szDisableRollback[] =
122 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
123 static const WCHAR szExecuteAction[] =
124 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
125 const WCHAR szFindRelatedProducts[] =
126 {'F','i','n','d','R','e','l','a','t','e','d',
127 'P','r','o','d','u','c','t','s',0};
128 static const WCHAR szInstallAdminPackage[] =
129 {'I','n','s','t','a','l','l','A','d','m','i','n',
130 'P','a','c','k','a','g','e',0};
131 static const WCHAR szInstallSFPCatalogFile[] =
132 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
133 'F','i','l','e',0};
134 static const WCHAR szIsolateComponents[] =
135 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
136 const WCHAR szMigrateFeatureStates[] =
137 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
138 'S','t','a','t','e','s',0};
139 const WCHAR szMoveFiles[] =
140 {'M','o','v','e','F','i','l','e','s',0};
141 static const WCHAR szMsiPublishAssemblies[] =
142 {'M','s','i','P','u','b','l','i','s','h',
143 'A','s','s','e','m','b','l','i','e','s',0};
144 static const WCHAR szMsiUnpublishAssemblies[] =
145 {'M','s','i','U','n','p','u','b','l','i','s','h',
146 'A','s','s','e','m','b','l','i','e','s',0};
147 static const WCHAR szInstallODBC[] =
148 {'I','n','s','t','a','l','l','O','D','B','C',0};
149 static const WCHAR szInstallServices[] =
150 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
151 const WCHAR szPatchFiles[] =
152 {'P','a','t','c','h','F','i','l','e','s',0};
153 static const WCHAR szPublishComponents[] =
154 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
155 static const WCHAR szRegisterComPlus[] =
156 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
157 const WCHAR szRegisterExtensionInfo[] =
158 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
159 'I','n','f','o',0};
160 static const WCHAR szRegisterFonts[] =
161 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
162 const WCHAR szRegisterMIMEInfo[] =
163 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
164 static const WCHAR szRegisterUser[] =
165 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
166 const WCHAR szRemoveDuplicateFiles[] =
167 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
168 'F','i','l','e','s',0};
169 static const WCHAR szRemoveEnvironmentStrings[] =
170 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
171 'S','t','r','i','n','g','s',0};
172 const WCHAR szRemoveExistingProducts[] =
173 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
174 'P','r','o','d','u','c','t','s',0};
175 const WCHAR szRemoveFiles[] =
176 {'R','e','m','o','v','e','F','i','l','e','s',0};
177 static const WCHAR szRemoveFolders[] =
178 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
179 static const WCHAR szRemoveIniValues[] =
180 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
181 static const WCHAR szRemoveODBC[] =
182 {'R','e','m','o','v','e','O','D','B','C',0};
183 static const WCHAR szRemoveRegistryValues[] =
184 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
185 'V','a','l','u','e','s',0};
186 static const WCHAR szRemoveShortcuts[] =
187 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
188 static const WCHAR szRMCCPSearch[] =
189 {'R','M','C','C','P','S','e','a','r','c','h',0};
190 static const WCHAR szScheduleReboot[] =
191 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
192 static const WCHAR szSelfUnregModules[] =
193 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
194 static const WCHAR szSetODBCFolders[] =
195 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
196 static const WCHAR szStartServices[] =
197 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
198 static const WCHAR szStopServices[] =
199 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
200 static const WCHAR szUnpublishComponents[] =
201 {'U','n','p','u','b','l','i','s','h',
202 'C','o','m','p','o','n','e','n','t','s',0};
203 static const WCHAR szUnpublishFeatures[] =
204 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
205 const WCHAR szUnregisterClassInfo[] =
206 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
207 'I','n','f','o',0};
208 static const WCHAR szUnregisterComPlus[] =
209 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
210 const WCHAR szUnregisterExtensionInfo[] =
211 {'U','n','r','e','g','i','s','t','e','r',
212 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
213 static const WCHAR szUnregisterFonts[] =
214 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
215 const WCHAR szUnregisterMIMEInfo[] =
216 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
217 const WCHAR szUnregisterProgIdInfo[] =
218 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
219 'I','n','f','o',0};
220 static const WCHAR szUnregisterTypeLibraries[] =
221 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
222 'L','i','b','r','a','r','i','e','s',0};
223 static const WCHAR szValidateProductID[] =
224 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
225 static const WCHAR szWriteEnvironmentStrings[] =
226 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
227 'S','t','r','i','n','g','s',0};
229 /* action handlers */
230 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
232 struct _actions {
233 LPCWSTR action;
234 STANDARDACTIONHANDLER handler;
238 /********************************************************
239 * helper functions
240 ********************************************************/
242 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
244 static const WCHAR Query_t[] =
245 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
246 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
247 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
248 ' ','\'','%','s','\'',0};
249 MSIRECORD * row;
251 row = MSI_QueryGetRecord( package->db, Query_t, action );
252 if (!row)
253 return;
254 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
255 msiobj_release(&row->hdr);
258 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
259 UINT rc)
261 MSIRECORD * row;
262 static const WCHAR template_s[]=
263 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
264 '%','s', '.',0};
265 static const WCHAR template_e[]=
266 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
267 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
268 '%','i','.',0};
269 static const WCHAR format[] =
270 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
271 WCHAR message[1024];
272 WCHAR timet[0x100];
274 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
275 if (start)
276 sprintfW(message,template_s,timet,action);
277 else
278 sprintfW(message,template_e,timet,action,rc);
280 row = MSI_CreateRecord(1);
281 MSI_RecordSetStringW(row,1,message);
283 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
284 msiobj_release(&row->hdr);
287 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
289 LPCWSTR ptr,ptr2;
290 BOOL quote;
291 DWORD len;
292 LPWSTR prop = NULL, val = NULL;
294 if (!szCommandLine)
295 return ERROR_SUCCESS;
297 ptr = szCommandLine;
299 while (*ptr)
301 if (*ptr==' ')
303 ptr++;
304 continue;
307 TRACE("Looking at %s\n",debugstr_w(ptr));
309 ptr2 = strchrW(ptr,'=');
310 if (!ptr2)
312 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
313 break;
316 quote = FALSE;
318 len = ptr2-ptr;
319 prop = msi_alloc((len+1)*sizeof(WCHAR));
320 memcpy(prop,ptr,len*sizeof(WCHAR));
321 prop[len]=0;
322 ptr2++;
324 len = 0;
325 ptr = ptr2;
326 while (*ptr && (quote || (!quote && *ptr!=' ')))
328 if (*ptr == '"')
329 quote = !quote;
330 ptr++;
331 len++;
334 if (*ptr2=='"')
336 ptr2++;
337 len -= 2;
339 val = msi_alloc((len+1)*sizeof(WCHAR));
340 memcpy(val,ptr2,len*sizeof(WCHAR));
341 val[len] = 0;
343 if (lstrlenW(prop) > 0)
345 TRACE("Found commandline property (%s) = (%s)\n",
346 debugstr_w(prop), debugstr_w(val));
347 MSI_SetPropertyW(package,prop,val);
349 msi_free(val);
350 msi_free(prop);
353 return ERROR_SUCCESS;
357 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
359 LPCWSTR pc;
360 LPWSTR p, *ret = NULL;
361 UINT count = 0;
363 if (!str)
364 return ret;
366 /* count the number of substrings */
367 for ( pc = str, count = 0; pc; count++ )
369 pc = strchrW( pc, sep );
370 if (pc)
371 pc++;
374 /* allocate space for an array of substring pointers and the substrings */
375 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
376 (lstrlenW(str)+1) * sizeof(WCHAR) );
377 if (!ret)
378 return ret;
380 /* copy the string and set the pointers */
381 p = (LPWSTR) &ret[count+1];
382 lstrcpyW( p, str );
383 for( count = 0; (ret[count] = p); count++ )
385 p = strchrW( p, sep );
386 if (p)
387 *p++ = 0;
390 return ret;
393 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
395 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
396 LPWSTR prod_code, patch_product;
397 UINT ret;
399 prod_code = msi_dup_property( package, szProductCode );
400 patch_product = msi_get_suminfo_product( patch );
402 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
404 if ( strstrW( patch_product, prod_code ) )
405 ret = ERROR_SUCCESS;
406 else
407 ret = ERROR_FUNCTION_FAILED;
409 msi_free( patch_product );
410 msi_free( prod_code );
412 return ret;
415 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
416 MSIDATABASE *patch_db, LPCWSTR name )
418 UINT ret = ERROR_FUNCTION_FAILED;
419 IStorage *stg = NULL;
420 HRESULT r;
422 TRACE("%p %s\n", package, debugstr_w(name) );
424 if (*name++ != ':')
426 ERR("expected a colon in %s\n", debugstr_w(name));
427 return ERROR_FUNCTION_FAILED;
430 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
431 if (SUCCEEDED(r))
433 ret = msi_check_transform_applicable( package, stg );
434 if (ret == ERROR_SUCCESS)
435 msi_table_apply_transform( package->db, stg );
436 else
437 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
438 IStorage_Release( stg );
440 else
441 ERR("failed to open substorage %s\n", debugstr_w(name));
443 return ERROR_SUCCESS;
446 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
448 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
449 LPWSTR guid_list, *guids, product_code;
450 UINT i, ret = ERROR_FUNCTION_FAILED;
452 product_code = msi_dup_property( package, szProdCode );
453 if (!product_code)
455 /* FIXME: the property ProductCode should be written into the DB somewhere */
456 ERR("no product code to check\n");
457 return ERROR_SUCCESS;
460 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
461 guids = msi_split_string( guid_list, ';' );
462 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
464 if (!lstrcmpW( guids[i], product_code ))
465 ret = ERROR_SUCCESS;
467 msi_free( guids );
468 msi_free( guid_list );
469 msi_free( product_code );
471 return ret;
474 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
476 MSISUMMARYINFO *si;
477 LPWSTR str, *substorage;
478 UINT i, r = ERROR_SUCCESS;
480 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
481 if (!si)
482 return ERROR_FUNCTION_FAILED;
484 msi_check_patch_applicable( package, si );
486 /* enumerate the substorage */
487 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
488 substorage = msi_split_string( str, ';' );
489 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
490 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
491 msi_free( substorage );
492 msi_free( str );
494 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
496 msiobj_release( &si->hdr );
498 return r;
501 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
503 MSIDATABASE *patch_db = NULL;
504 UINT r;
506 TRACE("%p %s\n", package, debugstr_w( file ) );
508 /* FIXME:
509 * We probably want to make sure we only open a patch collection here.
510 * Patch collections (.msp) and databases (.msi) have different GUIDs
511 * but currently MSI_OpenDatabaseW will accept both.
513 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
514 if ( r != ERROR_SUCCESS )
516 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
517 return r;
520 msi_parse_patch_summary( package, patch_db );
523 * There might be a CAB file in the patch package,
524 * so append it to the list of storage to search for streams.
526 append_storage_to_db( package->db, patch_db->storage );
528 msiobj_release( &patch_db->hdr );
530 return ERROR_SUCCESS;
533 /* get the PATCH property, and apply all the patches it specifies */
534 static UINT msi_apply_patches( MSIPACKAGE *package )
536 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
537 LPWSTR patch_list, *patches;
538 UINT i, r = ERROR_SUCCESS;
540 patch_list = msi_dup_property( package, szPatch );
542 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
544 patches = msi_split_string( patch_list, ';' );
545 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
546 r = msi_apply_patch_package( package, patches[i] );
548 msi_free( patches );
549 msi_free( patch_list );
551 return r;
554 static UINT msi_apply_transforms( MSIPACKAGE *package )
556 static const WCHAR szTransforms[] = {
557 'T','R','A','N','S','F','O','R','M','S',0 };
558 LPWSTR xform_list, *xforms;
559 UINT i, r = ERROR_SUCCESS;
561 xform_list = msi_dup_property( package, szTransforms );
562 xforms = msi_split_string( xform_list, ';' );
564 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
566 if (xforms[i][0] == ':')
567 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
568 else
569 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
572 msi_free( xforms );
573 msi_free( xform_list );
575 return r;
578 static BOOL ui_sequence_exists( MSIPACKAGE *package )
580 MSIQUERY *view;
581 UINT rc;
583 static const WCHAR ExecSeqQuery [] =
584 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
585 '`','I','n','s','t','a','l','l',
586 'U','I','S','e','q','u','e','n','c','e','`',
587 ' ','W','H','E','R','E',' ',
588 '`','S','e','q','u','e','n','c','e','`',' ',
589 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
590 '`','S','e','q','u','e','n','c','e','`',0};
592 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
593 if (rc == ERROR_SUCCESS)
595 msiobj_release(&view->hdr);
596 return TRUE;
599 return FALSE;
602 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
604 LPWSTR p, db;
605 LPWSTR source, check;
606 DWORD len;
608 static const WCHAR szOriginalDatabase[] =
609 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
611 db = msi_dup_property( package, szOriginalDatabase );
612 if (!db)
613 return ERROR_OUTOFMEMORY;
615 p = strrchrW( db, '\\' );
616 if (!p)
618 p = strrchrW( db, '/' );
619 if (!p)
621 msi_free(db);
622 return ERROR_SUCCESS;
626 len = p - db + 2;
627 source = msi_alloc( len * sizeof(WCHAR) );
628 lstrcpynW( source, db, len );
630 check = msi_dup_property( package, cszSourceDir );
631 if (!check || replace)
632 MSI_SetPropertyW( package, cszSourceDir, source );
634 msi_free( check );
636 check = msi_dup_property( package, cszSOURCEDIR );
637 if (!check || replace)
638 MSI_SetPropertyW( package, cszSOURCEDIR, source );
640 msi_free( check );
641 msi_free( source );
642 msi_free( db );
644 return ERROR_SUCCESS;
647 /****************************************************
648 * TOP level entry points
649 *****************************************************/
651 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
652 LPCWSTR szCommandLine )
654 UINT rc;
655 BOOL ui = FALSE, ui_exists;
656 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
657 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
658 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
660 MSI_SetPropertyW(package, szAction, szInstall);
662 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
664 package->script->InWhatSequence = SEQUENCE_INSTALL;
666 if (szPackagePath)
668 LPWSTR p, dir;
669 LPCWSTR file;
671 dir = strdupW(szPackagePath);
672 p = strrchrW(dir, '\\');
673 if (p)
675 *(++p) = 0;
676 file = szPackagePath + (p - dir);
678 else
680 msi_free(dir);
681 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
682 GetCurrentDirectoryW(MAX_PATH, dir);
683 lstrcatW(dir, cszbs);
684 file = szPackagePath;
687 msi_free( package->PackagePath );
688 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
689 if (!package->PackagePath)
691 msi_free(dir);
692 return ERROR_OUTOFMEMORY;
695 lstrcpyW(package->PackagePath, dir);
696 lstrcatW(package->PackagePath, file);
697 msi_free(dir);
699 msi_set_sourcedir_props(package, FALSE);
702 msi_parse_command_line( package, szCommandLine );
704 msi_apply_transforms( package );
705 msi_apply_patches( package );
707 /* properties may have been added by a transform */
708 msi_clone_properties( package );
710 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
712 package->script->InWhatSequence |= SEQUENCE_UI;
713 rc = ACTION_ProcessUISequence(package);
714 ui = TRUE;
715 ui_exists = ui_sequence_exists(package);
716 if (rc == ERROR_SUCCESS || !ui_exists)
718 package->script->InWhatSequence |= SEQUENCE_EXEC;
719 rc = ACTION_ProcessExecSequence(package,ui_exists);
722 else
723 rc = ACTION_ProcessExecSequence(package,FALSE);
725 package->script->CurrentlyScripting= FALSE;
727 /* process the ending type action */
728 if (rc == ERROR_SUCCESS)
729 ACTION_PerformActionSequence(package,-1,ui);
730 else if (rc == ERROR_INSTALL_USEREXIT)
731 ACTION_PerformActionSequence(package,-2,ui);
732 else if (rc == ERROR_INSTALL_SUSPEND)
733 ACTION_PerformActionSequence(package,-4,ui);
734 else /* failed */
735 ACTION_PerformActionSequence(package,-3,ui);
737 /* finish up running custom actions */
738 ACTION_FinishCustomActions(package);
740 return rc;
743 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
745 UINT rc = ERROR_SUCCESS;
746 MSIRECORD * row = 0;
747 static const WCHAR ExecSeqQuery[] =
748 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
749 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
750 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
751 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
753 static const WCHAR UISeqQuery[] =
754 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
755 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
756 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
757 ' ', '=',' ','%','i',0};
759 if (UI)
760 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
761 else
762 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
764 if (row)
766 LPCWSTR action, cond;
768 TRACE("Running the actions\n");
770 /* check conditions */
771 cond = MSI_RecordGetString(row,2);
773 /* this is a hack to skip errors in the condition code */
774 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
775 goto end;
777 action = MSI_RecordGetString(row,1);
778 if (!action)
780 ERR("failed to fetch action\n");
781 rc = ERROR_FUNCTION_FAILED;
782 goto end;
785 if (UI)
786 rc = ACTION_PerformUIAction(package,action,-1);
787 else
788 rc = ACTION_PerformAction(package,action,-1,FALSE);
789 end:
790 msiobj_release(&row->hdr);
792 else
793 rc = ERROR_SUCCESS;
795 return rc;
798 typedef struct {
799 MSIPACKAGE* package;
800 BOOL UI;
801 } iterate_action_param;
803 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
805 iterate_action_param *iap= (iterate_action_param*)param;
806 UINT rc;
807 LPCWSTR cond, action;
809 action = MSI_RecordGetString(row,1);
810 if (!action)
812 ERR("Error is retrieving action name\n");
813 return ERROR_FUNCTION_FAILED;
816 /* check conditions */
817 cond = MSI_RecordGetString(row,2);
819 /* this is a hack to skip errors in the condition code */
820 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
822 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
823 return ERROR_SUCCESS;
826 if (iap->UI)
827 rc = ACTION_PerformUIAction(iap->package,action,-1);
828 else
829 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
831 msi_dialog_check_messages( NULL );
833 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
834 rc = iap->package->CurrentInstallState;
836 if (rc == ERROR_FUNCTION_NOT_CALLED)
837 rc = ERROR_SUCCESS;
839 if (rc != ERROR_SUCCESS)
840 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
842 return rc;
845 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
847 MSIQUERY * view;
848 UINT r;
849 static const WCHAR query[] =
850 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
851 '`','%','s','`',
852 ' ','W','H','E','R','E',' ',
853 '`','S','e','q','u','e','n','c','e','`',' ',
854 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
855 '`','S','e','q','u','e','n','c','e','`',0};
856 iterate_action_param iap;
859 * FIXME: probably should be checking UILevel in the
860 * ACTION_PerformUIAction/ACTION_PerformAction
861 * rather than saving the UI level here. Those
862 * two functions can be merged too.
864 iap.package = package;
865 iap.UI = TRUE;
867 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
869 r = MSI_OpenQuery( package->db, &view, query, szTable );
870 if (r == ERROR_SUCCESS)
872 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
873 msiobj_release(&view->hdr);
876 return r;
879 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
881 MSIQUERY * view;
882 UINT rc;
883 static const WCHAR ExecSeqQuery[] =
884 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
885 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
886 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
887 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
888 'O','R','D','E','R',' ', 'B','Y',' ',
889 '`','S','e','q','u','e','n','c','e','`',0 };
890 MSIRECORD * row = 0;
891 static const WCHAR IVQuery[] =
892 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
893 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
894 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
895 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
896 ' ','\'', 'I','n','s','t','a','l','l',
897 'V','a','l','i','d','a','t','e','\'', 0};
898 INT seq = 0;
899 iterate_action_param iap;
901 iap.package = package;
902 iap.UI = FALSE;
904 if (package->script->ExecuteSequenceRun)
906 TRACE("Execute Sequence already Run\n");
907 return ERROR_SUCCESS;
910 package->script->ExecuteSequenceRun = TRUE;
912 /* get the sequence number */
913 if (UIran)
915 row = MSI_QueryGetRecord(package->db, IVQuery);
916 if( !row )
917 return ERROR_FUNCTION_FAILED;
918 seq = MSI_RecordGetInteger(row,1);
919 msiobj_release(&row->hdr);
922 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
923 if (rc == ERROR_SUCCESS)
925 TRACE("Running the actions\n");
927 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
928 msiobj_release(&view->hdr);
931 return rc;
934 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
936 MSIQUERY * view;
937 UINT rc;
938 static const WCHAR ExecSeqQuery [] =
939 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
940 '`','I','n','s','t','a','l','l',
941 'U','I','S','e','q','u','e','n','c','e','`',
942 ' ','W','H','E','R','E',' ',
943 '`','S','e','q','u','e','n','c','e','`',' ',
944 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
945 '`','S','e','q','u','e','n','c','e','`',0};
946 iterate_action_param iap;
948 iap.package = package;
949 iap.UI = TRUE;
951 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
953 if (rc == ERROR_SUCCESS)
955 TRACE("Running the actions\n");
957 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
958 msiobj_release(&view->hdr);
961 return rc;
964 /********************************************************
965 * ACTION helper functions and functions that perform the actions
966 *******************************************************/
967 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
968 UINT* rc, UINT script, BOOL force )
970 BOOL ret=FALSE;
971 UINT arc;
973 arc = ACTION_CustomAction(package, action, script, force);
975 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
977 *rc = arc;
978 ret = TRUE;
980 return ret;
984 * A lot of actions are really important even if they don't do anything
985 * explicit... Lots of properties are set at the beginning of the installation
986 * CostFinalize does a bunch of work to translate the directories and such
988 * But until I get write access to the database that is hard, so I am going to
989 * hack it to see if I can get something to run.
991 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
993 UINT rc = ERROR_SUCCESS;
994 BOOL handled;
996 TRACE("Performing action (%s)\n",debugstr_w(action));
998 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1000 if (!handled)
1001 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1003 if (!handled)
1005 WARN("unhandled msi action %s\n",debugstr_w(action));
1006 rc = ERROR_FUNCTION_NOT_CALLED;
1009 return rc;
1012 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1014 UINT rc = ERROR_SUCCESS;
1015 BOOL handled = FALSE;
1017 TRACE("Performing action (%s)\n",debugstr_w(action));
1019 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1021 if (!handled)
1022 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1024 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1025 handled = TRUE;
1027 if (!handled)
1029 WARN("unhandled msi action %s\n",debugstr_w(action));
1030 rc = ERROR_FUNCTION_NOT_CALLED;
1033 return rc;
1038 * Actual Action Handlers
1041 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1043 MSIPACKAGE *package = (MSIPACKAGE*)param;
1044 LPCWSTR dir;
1045 LPWSTR full_path;
1046 MSIRECORD *uirow;
1047 MSIFOLDER *folder;
1049 dir = MSI_RecordGetString(row,1);
1050 if (!dir)
1052 ERR("Unable to get folder id\n");
1053 return ERROR_SUCCESS;
1056 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1057 if (!full_path)
1059 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1060 return ERROR_SUCCESS;
1063 TRACE("Folder is %s\n",debugstr_w(full_path));
1065 /* UI stuff */
1066 uirow = MSI_CreateRecord(1);
1067 MSI_RecordSetStringW(uirow,1,full_path);
1068 ui_actiondata(package,szCreateFolders,uirow);
1069 msiobj_release( &uirow->hdr );
1071 if (folder->State == 0)
1072 create_full_pathW(full_path);
1074 folder->State = 3;
1076 msi_free(full_path);
1077 return ERROR_SUCCESS;
1080 /* FIXME: probably should merge this with the above function */
1081 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1083 UINT rc = ERROR_SUCCESS;
1084 MSIFOLDER *folder;
1085 LPWSTR install_path;
1087 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1088 if (!install_path)
1089 return ERROR_FUNCTION_FAILED;
1091 /* create the path */
1092 if (folder->State == 0)
1094 create_full_pathW(install_path);
1095 folder->State = 2;
1097 msi_free(install_path);
1099 return rc;
1102 UINT msi_create_component_directories( MSIPACKAGE *package )
1104 MSICOMPONENT *comp;
1106 /* create all the folders required by the components are going to install */
1107 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1109 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1110 continue;
1111 msi_create_directory( package, comp->Directory );
1114 return ERROR_SUCCESS;
1118 * Also we cannot enable/disable components either, so for now I am just going
1119 * to do all the directories for all the components.
1121 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1123 static const WCHAR ExecSeqQuery[] =
1124 {'S','E','L','E','C','T',' ',
1125 '`','D','i','r','e','c','t','o','r','y','_','`',
1126 ' ','F','R','O','M',' ',
1127 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1128 UINT rc;
1129 MSIQUERY *view;
1131 /* create all the empty folders specified in the CreateFolder table */
1132 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1133 if (rc != ERROR_SUCCESS)
1134 return ERROR_SUCCESS;
1136 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1137 msiobj_release(&view->hdr);
1139 msi_create_component_directories( package );
1141 return rc;
1144 static UINT load_component( MSIRECORD *row, LPVOID param )
1146 MSIPACKAGE *package = param;
1147 MSICOMPONENT *comp;
1149 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1150 if (!comp)
1151 return ERROR_FUNCTION_FAILED;
1153 list_add_tail( &package->components, &comp->entry );
1155 /* fill in the data */
1156 comp->Component = msi_dup_record_field( row, 1 );
1158 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1160 comp->ComponentId = msi_dup_record_field( row, 2 );
1161 comp->Directory = msi_dup_record_field( row, 3 );
1162 comp->Attributes = MSI_RecordGetInteger(row,4);
1163 comp->Condition = msi_dup_record_field( row, 5 );
1164 comp->KeyPath = msi_dup_record_field( row, 6 );
1166 comp->Installed = INSTALLSTATE_UNKNOWN;
1167 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1169 return ERROR_SUCCESS;
1172 static UINT load_all_components( MSIPACKAGE *package )
1174 static const WCHAR query[] = {
1175 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1176 '`','C','o','m','p','o','n','e','n','t','`',0 };
1177 MSIQUERY *view;
1178 UINT r;
1180 if (!list_empty(&package->components))
1181 return ERROR_SUCCESS;
1183 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1184 if (r != ERROR_SUCCESS)
1185 return r;
1187 r = MSI_IterateRecords(view, NULL, load_component, package);
1188 msiobj_release(&view->hdr);
1189 return r;
1192 typedef struct {
1193 MSIPACKAGE *package;
1194 MSIFEATURE *feature;
1195 } _ilfs;
1197 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1199 ComponentList *cl;
1201 cl = msi_alloc( sizeof (*cl) );
1202 if ( !cl )
1203 return ERROR_NOT_ENOUGH_MEMORY;
1204 cl->component = comp;
1205 list_add_tail( &feature->Components, &cl->entry );
1207 return ERROR_SUCCESS;
1210 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1212 FeatureList *fl;
1214 fl = msi_alloc( sizeof(*fl) );
1215 if ( !fl )
1216 return ERROR_NOT_ENOUGH_MEMORY;
1217 fl->feature = child;
1218 list_add_tail( &parent->Children, &fl->entry );
1220 return ERROR_SUCCESS;
1223 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1225 _ilfs* ilfs= (_ilfs*)param;
1226 LPCWSTR component;
1227 MSICOMPONENT *comp;
1229 component = MSI_RecordGetString(row,1);
1231 /* check to see if the component is already loaded */
1232 comp = get_loaded_component( ilfs->package, component );
1233 if (!comp)
1235 ERR("unknown component %s\n", debugstr_w(component));
1236 return ERROR_FUNCTION_FAILED;
1239 add_feature_component( ilfs->feature, comp );
1240 comp->Enabled = TRUE;
1242 return ERROR_SUCCESS;
1245 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1247 MSIFEATURE *feature;
1249 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1251 if ( !lstrcmpW( feature->Feature, name ) )
1252 return feature;
1255 return NULL;
1258 static UINT load_feature(MSIRECORD * row, LPVOID param)
1260 MSIPACKAGE* package = (MSIPACKAGE*)param;
1261 MSIFEATURE* feature;
1262 static const WCHAR Query1[] =
1263 {'S','E','L','E','C','T',' ',
1264 '`','C','o','m','p','o','n','e','n','t','_','`',
1265 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1266 'C','o','m','p','o','n','e','n','t','s','`',' ',
1267 'W','H','E','R','E',' ',
1268 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1269 MSIQUERY * view;
1270 UINT rc;
1271 _ilfs ilfs;
1273 /* fill in the data */
1275 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1276 if (!feature)
1277 return ERROR_NOT_ENOUGH_MEMORY;
1279 list_init( &feature->Children );
1280 list_init( &feature->Components );
1282 feature->Feature = msi_dup_record_field( row, 1 );
1284 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1286 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1287 feature->Title = msi_dup_record_field( row, 3 );
1288 feature->Description = msi_dup_record_field( row, 4 );
1290 if (!MSI_RecordIsNull(row,5))
1291 feature->Display = MSI_RecordGetInteger(row,5);
1293 feature->Level= MSI_RecordGetInteger(row,6);
1294 feature->Directory = msi_dup_record_field( row, 7 );
1295 feature->Attributes = MSI_RecordGetInteger(row,8);
1297 feature->Installed = INSTALLSTATE_UNKNOWN;
1298 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1300 list_add_tail( &package->features, &feature->entry );
1302 /* load feature components */
1304 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1305 if (rc != ERROR_SUCCESS)
1306 return ERROR_SUCCESS;
1308 ilfs.package = package;
1309 ilfs.feature = feature;
1311 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1312 msiobj_release(&view->hdr);
1314 return ERROR_SUCCESS;
1317 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1319 MSIPACKAGE* package = (MSIPACKAGE*)param;
1320 MSIFEATURE *parent, *child;
1322 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1323 if (!child)
1324 return ERROR_FUNCTION_FAILED;
1326 if (!child->Feature_Parent)
1327 return ERROR_SUCCESS;
1329 parent = find_feature_by_name( package, child->Feature_Parent );
1330 if (!parent)
1331 return ERROR_FUNCTION_FAILED;
1333 add_feature_child( parent, child );
1334 return ERROR_SUCCESS;
1337 static UINT load_all_features( MSIPACKAGE *package )
1339 static const WCHAR query[] = {
1340 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1341 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1342 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1343 MSIQUERY *view;
1344 UINT r;
1346 if (!list_empty(&package->features))
1347 return ERROR_SUCCESS;
1349 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1350 if (r != ERROR_SUCCESS)
1351 return r;
1353 r = MSI_IterateRecords( view, NULL, load_feature, package );
1354 if (r != ERROR_SUCCESS)
1355 return r;
1357 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1358 msiobj_release( &view->hdr );
1360 return r;
1363 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1365 if (!p)
1366 return p;
1367 p = strchrW(p, ch);
1368 if (!p)
1369 return p;
1370 *p = 0;
1371 return p+1;
1374 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1376 static const WCHAR query[] = {
1377 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1378 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1379 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1380 MSIQUERY *view = NULL;
1381 MSIRECORD *row = NULL;
1382 UINT r;
1384 TRACE("%s\n", debugstr_w(file->File));
1386 r = MSI_OpenQuery(package->db, &view, query, file->File);
1387 if (r != ERROR_SUCCESS)
1388 goto done;
1390 r = MSI_ViewExecute(view, NULL);
1391 if (r != ERROR_SUCCESS)
1392 goto done;
1394 r = MSI_ViewFetch(view, &row);
1395 if (r != ERROR_SUCCESS)
1396 goto done;
1398 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1399 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1400 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1401 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1402 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1404 done:
1405 if (view) msiobj_release(&view->hdr);
1406 if (row) msiobj_release(&row->hdr);
1407 return r;
1410 static UINT load_file(MSIRECORD *row, LPVOID param)
1412 MSIPACKAGE* package = (MSIPACKAGE*)param;
1413 LPCWSTR component;
1414 MSIFILE *file;
1416 /* fill in the data */
1418 file = msi_alloc_zero( sizeof (MSIFILE) );
1419 if (!file)
1420 return ERROR_NOT_ENOUGH_MEMORY;
1422 file->File = msi_dup_record_field( row, 1 );
1424 component = MSI_RecordGetString( row, 2 );
1425 file->Component = get_loaded_component( package, component );
1427 if (!file->Component)
1428 ERR("Unfound Component %s\n",debugstr_w(component));
1430 file->FileName = msi_dup_record_field( row, 3 );
1431 reduce_to_longfilename( file->FileName );
1433 file->ShortName = msi_dup_record_field( row, 3 );
1434 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1436 file->FileSize = MSI_RecordGetInteger( row, 4 );
1437 file->Version = msi_dup_record_field( row, 5 );
1438 file->Language = msi_dup_record_field( row, 6 );
1439 file->Attributes = MSI_RecordGetInteger( row, 7 );
1440 file->Sequence = MSI_RecordGetInteger( row, 8 );
1442 file->state = msifs_invalid;
1444 /* if the compressed bits are not set in the file attributes,
1445 * then read the information from the package word count property
1447 if (file->Attributes & msidbFileAttributesCompressed)
1449 file->IsCompressed = TRUE;
1451 else if (file->Attributes & msidbFileAttributesNoncompressed)
1453 file->IsCompressed = FALSE;
1455 else
1457 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1460 load_file_hash(package, file);
1462 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1464 list_add_tail( &package->files, &file->entry );
1466 return ERROR_SUCCESS;
1469 static UINT load_all_files(MSIPACKAGE *package)
1471 MSIQUERY * view;
1472 UINT rc;
1473 static const WCHAR Query[] =
1474 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1475 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1476 '`','S','e','q','u','e','n','c','e','`', 0};
1478 if (!list_empty(&package->files))
1479 return ERROR_SUCCESS;
1481 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1482 if (rc != ERROR_SUCCESS)
1483 return ERROR_SUCCESS;
1485 rc = MSI_IterateRecords(view, NULL, load_file, package);
1486 msiobj_release(&view->hdr);
1488 return ERROR_SUCCESS;
1491 static UINT load_folder( MSIRECORD *row, LPVOID param )
1493 MSIPACKAGE *package = param;
1494 static const WCHAR szDot[] = { '.',0 };
1495 static WCHAR szEmpty[] = { 0 };
1496 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1497 MSIFOLDER *folder;
1499 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1500 if (!folder)
1501 return ERROR_NOT_ENOUGH_MEMORY;
1503 folder->Directory = msi_dup_record_field( row, 1 );
1505 TRACE("%s\n", debugstr_w(folder->Directory));
1507 p = msi_dup_record_field(row, 3);
1509 /* split src and target dir */
1510 tgt_short = p;
1511 src_short = folder_split_path( p, ':' );
1513 /* split the long and short paths */
1514 tgt_long = folder_split_path( tgt_short, '|' );
1515 src_long = folder_split_path( src_short, '|' );
1517 /* check for no-op dirs */
1518 if (!lstrcmpW(szDot, tgt_short))
1519 tgt_short = szEmpty;
1520 if (!lstrcmpW(szDot, src_short))
1521 src_short = szEmpty;
1523 if (!tgt_long)
1524 tgt_long = tgt_short;
1526 if (!src_short) {
1527 src_short = tgt_short;
1528 src_long = tgt_long;
1531 if (!src_long)
1532 src_long = src_short;
1534 /* FIXME: use the target short path too */
1535 folder->TargetDefault = strdupW(tgt_long);
1536 folder->SourceShortPath = strdupW(src_short);
1537 folder->SourceLongPath = strdupW(src_long);
1538 msi_free(p);
1540 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1541 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1542 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1544 folder->Parent = msi_dup_record_field( row, 2 );
1546 folder->Property = msi_dup_property( package, folder->Directory );
1548 list_add_tail( &package->folders, &folder->entry );
1550 TRACE("returning %p\n", folder);
1552 return ERROR_SUCCESS;
1555 static UINT load_all_folders( MSIPACKAGE *package )
1557 static const WCHAR query[] = {
1558 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1559 '`','D','i','r','e','c','t','o','r','y','`',0 };
1560 MSIQUERY *view;
1561 UINT r;
1563 if (!list_empty(&package->folders))
1564 return ERROR_SUCCESS;
1566 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1567 if (r != ERROR_SUCCESS)
1568 return r;
1570 r = MSI_IterateRecords(view, NULL, load_folder, package);
1571 msiobj_release(&view->hdr);
1572 return r;
1576 * I am not doing any of the costing functionality yet.
1577 * Mostly looking at doing the Component and Feature loading
1579 * The native MSI does A LOT of modification to tables here. Mostly adding
1580 * a lot of temporary columns to the Feature and Component tables.
1582 * note: Native msi also tracks the short filename. But I am only going to
1583 * track the long ones. Also looking at this directory table
1584 * it appears that the directory table does not get the parents
1585 * resolved base on property only based on their entries in the
1586 * directory table.
1588 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1590 static const WCHAR szCosting[] =
1591 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1592 static const WCHAR szZero[] = { '0', 0 };
1594 MSI_SetPropertyW(package, szCosting, szZero);
1595 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1597 load_all_components( package );
1598 load_all_features( package );
1599 load_all_files( package );
1600 load_all_folders( package );
1602 return ERROR_SUCCESS;
1605 static UINT execute_script(MSIPACKAGE *package, UINT script )
1607 UINT i;
1608 UINT rc = ERROR_SUCCESS;
1610 TRACE("Executing Script %i\n",script);
1612 if (!package->script)
1614 ERR("no script!\n");
1615 return ERROR_FUNCTION_FAILED;
1618 for (i = 0; i < package->script->ActionCount[script]; i++)
1620 LPWSTR action;
1621 action = package->script->Actions[script][i];
1622 ui_actionstart(package, action);
1623 TRACE("Executing Action (%s)\n",debugstr_w(action));
1624 rc = ACTION_PerformAction(package, action, script, TRUE);
1625 if (rc != ERROR_SUCCESS)
1626 break;
1628 msi_free_action_script(package, script);
1629 return rc;
1632 static UINT ACTION_FileCost(MSIPACKAGE *package)
1634 return ERROR_SUCCESS;
1637 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1639 MSICOMPONENT *comp;
1641 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1643 INSTALLSTATE res;
1645 if (!comp->ComponentId)
1646 continue;
1648 res = MsiGetComponentPathW( package->ProductCode,
1649 comp->ComponentId, NULL, NULL);
1650 if (res < 0)
1651 res = INSTALLSTATE_ABSENT;
1652 comp->Installed = res;
1656 /* scan for and update current install states */
1657 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1659 MSICOMPONENT *comp;
1660 MSIFEATURE *feature;
1662 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1664 ComponentList *cl;
1665 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1667 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1669 comp= cl->component;
1671 if (!comp->ComponentId)
1673 res = INSTALLSTATE_ABSENT;
1674 break;
1677 if (res == INSTALLSTATE_ABSENT)
1678 res = comp->Installed;
1679 else
1681 if (res == comp->Installed)
1682 continue;
1684 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1685 res != INSTALLSTATE_SOURCE)
1687 res = INSTALLSTATE_INCOMPLETE;
1691 feature->Installed = res;
1695 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1696 INSTALLSTATE state)
1698 static const WCHAR all[]={'A','L','L',0};
1699 LPWSTR override;
1700 MSIFEATURE *feature;
1702 override = msi_dup_property( package, property );
1703 if (!override)
1704 return FALSE;
1706 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1708 if (strcmpiW(override,all)==0)
1709 msi_feature_set_state( feature, state );
1710 else
1712 LPWSTR ptr = override;
1713 LPWSTR ptr2 = strchrW(override,',');
1715 while (ptr)
1717 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1718 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1720 msi_feature_set_state( feature, state );
1721 break;
1723 if (ptr2)
1725 ptr=ptr2+1;
1726 ptr2 = strchrW(ptr,',');
1728 else
1729 break;
1733 msi_free(override);
1735 return TRUE;
1738 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1740 int install_level;
1741 static const WCHAR szlevel[] =
1742 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1743 static const WCHAR szAddLocal[] =
1744 {'A','D','D','L','O','C','A','L',0};
1745 static const WCHAR szAddSource[] =
1746 {'A','D','D','S','O','U','R','C','E',0};
1747 static const WCHAR szRemove[] =
1748 {'R','E','M','O','V','E',0};
1749 static const WCHAR szReinstall[] =
1750 {'R','E','I','N','S','T','A','L','L',0};
1751 BOOL override = FALSE;
1752 MSICOMPONENT* component;
1753 MSIFEATURE *feature;
1756 /* I do not know if this is where it should happen.. but */
1758 TRACE("Checking Install Level\n");
1760 install_level = msi_get_property_int( package, szlevel, 1 );
1762 /* ok here is the _real_ rub
1763 * all these activation/deactivation things happen in order and things
1764 * later on the list override things earlier on the list.
1765 * 1) INSTALLLEVEL processing
1766 * 2) ADDLOCAL
1767 * 3) REMOVE
1768 * 4) ADDSOURCE
1769 * 5) ADDDEFAULT
1770 * 6) REINSTALL
1771 * 7) COMPADDLOCAL
1772 * 8) COMPADDSOURCE
1773 * 9) FILEADDLOCAL
1774 * 10) FILEADDSOURCE
1775 * 11) FILEADDDEFAULT
1776 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1777 * ignored for all the features. seems strange, especially since it is not
1778 * documented anywhere, but it is how it works.
1780 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1781 * REMOVE are the big ones, since we don't handle administrative installs
1782 * yet anyway.
1784 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1785 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1786 override |= process_state_property(package,szAddSource,INSTALLSTATE_SOURCE);
1787 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1789 if (!override)
1791 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1793 BOOL feature_state = ((feature->Level > 0) &&
1794 (feature->Level <= install_level));
1796 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1798 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1799 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1800 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1801 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1802 else
1803 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1807 /* disable child features of unselected parent features */
1808 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1810 FeatureList *fl;
1812 if (feature->Level > 0 && feature->Level <= install_level)
1813 continue;
1815 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1816 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1819 else
1821 /* set the Preselected Property */
1822 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1823 static const WCHAR szOne[] = { '1', 0 };
1825 MSI_SetPropertyW(package,szPreselected,szOne);
1829 * now we want to enable or disable components base on feature
1832 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1834 ComponentList *cl;
1836 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1837 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1839 /* features with components that have compressed files are made local */
1840 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1842 if (cl->component->Enabled &&
1843 cl->component->ForceLocalState &&
1844 feature->Action == INSTALLSTATE_SOURCE)
1846 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1847 break;
1851 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1853 component = cl->component;
1855 if (!component->Enabled)
1856 continue;
1858 switch (feature->Action)
1860 case INSTALLSTATE_ABSENT:
1861 component->anyAbsent = 1;
1862 break;
1863 case INSTALLSTATE_ADVERTISED:
1864 component->hasAdvertiseFeature = 1;
1865 break;
1866 case INSTALLSTATE_SOURCE:
1867 component->hasSourceFeature = 1;
1868 break;
1869 case INSTALLSTATE_LOCAL:
1870 component->hasLocalFeature = 1;
1871 break;
1872 case INSTALLSTATE_DEFAULT:
1873 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1874 component->hasAdvertiseFeature = 1;
1875 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1876 component->hasSourceFeature = 1;
1877 else
1878 component->hasLocalFeature = 1;
1879 break;
1880 default:
1881 break;
1886 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1888 /* if the component isn't enabled, leave it alone */
1889 if (!component->Enabled)
1890 continue;
1892 /* check if it's local or source */
1893 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1894 (component->hasLocalFeature || component->hasSourceFeature))
1896 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1897 !component->ForceLocalState)
1898 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1899 else
1900 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1901 continue;
1904 /* if any feature is local, the component must be local too */
1905 if (component->hasLocalFeature)
1907 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1908 continue;
1911 if (component->hasSourceFeature)
1913 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1914 continue;
1917 if (component->hasAdvertiseFeature)
1919 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1920 continue;
1923 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1924 if (component->anyAbsent)
1925 msi_component_set_state(component, INSTALLSTATE_ABSENT);
1928 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1930 if (component->Action == INSTALLSTATE_DEFAULT)
1932 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1933 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1936 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1937 debugstr_w(component->Component), component->Installed, component->Action);
1941 return ERROR_SUCCESS;
1944 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1946 MSIPACKAGE *package = (MSIPACKAGE*)param;
1947 LPCWSTR name;
1948 LPWSTR path;
1949 MSIFOLDER *f;
1951 name = MSI_RecordGetString(row,1);
1953 f = get_loaded_folder(package, name);
1954 if (!f) return ERROR_SUCCESS;
1956 /* reset the ResolvedTarget */
1957 msi_free(f->ResolvedTarget);
1958 f->ResolvedTarget = NULL;
1960 /* This helper function now does ALL the work */
1961 TRACE("Dir %s ...\n",debugstr_w(name));
1962 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1963 TRACE("resolves to %s\n",debugstr_w(path));
1964 msi_free(path);
1966 return ERROR_SUCCESS;
1969 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1971 MSIPACKAGE *package = (MSIPACKAGE*)param;
1972 LPCWSTR name;
1973 MSIFEATURE *feature;
1975 name = MSI_RecordGetString( row, 1 );
1977 feature = get_loaded_feature( package, name );
1978 if (!feature)
1979 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1980 else
1982 LPCWSTR Condition;
1983 Condition = MSI_RecordGetString(row,3);
1985 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1987 int level = MSI_RecordGetInteger(row,2);
1988 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1989 feature->Level = level;
1992 return ERROR_SUCCESS;
1995 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1997 static const WCHAR name_fmt[] =
1998 {'%','u','.','%','u','.','%','u','.','%','u',0};
1999 static WCHAR name[] = {'\\',0};
2000 VS_FIXEDFILEINFO *lpVer;
2001 WCHAR filever[0x100];
2002 LPVOID version;
2003 DWORD versize;
2004 DWORD handle;
2005 UINT sz;
2007 TRACE("%s\n", debugstr_w(filename));
2009 versize = GetFileVersionInfoSizeW( filename, &handle );
2010 if (!versize)
2011 return NULL;
2013 version = msi_alloc( versize );
2014 GetFileVersionInfoW( filename, 0, versize, version );
2016 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2018 msi_free( version );
2019 return NULL;
2022 sprintfW( filever, name_fmt,
2023 HIWORD(lpVer->dwFileVersionMS),
2024 LOWORD(lpVer->dwFileVersionMS),
2025 HIWORD(lpVer->dwFileVersionLS),
2026 LOWORD(lpVer->dwFileVersionLS));
2028 msi_free( version );
2030 return strdupW( filever );
2033 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2035 LPWSTR file_version;
2036 MSIFILE *file;
2038 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2040 MSICOMPONENT* comp = file->Component;
2041 LPWSTR p;
2043 if (!comp)
2044 continue;
2046 if (file->IsCompressed)
2047 comp->ForceLocalState = TRUE;
2049 /* calculate target */
2050 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2052 msi_free(file->TargetPath);
2054 TRACE("file %s is named %s\n",
2055 debugstr_w(file->File), debugstr_w(file->FileName));
2057 file->TargetPath = build_directory_name(2, p, file->FileName);
2059 msi_free(p);
2061 TRACE("file %s resolves to %s\n",
2062 debugstr_w(file->File), debugstr_w(file->TargetPath));
2064 /* don't check files of components that aren't installed */
2065 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2066 comp->Installed == INSTALLSTATE_ABSENT)
2068 file->state = msifs_missing; /* assume files are missing */
2069 continue;
2072 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2074 file->state = msifs_missing;
2075 comp->Cost += file->FileSize;
2076 comp->Installed = INSTALLSTATE_INCOMPLETE;
2077 continue;
2080 if (file->Version &&
2081 (file_version = msi_get_disk_file_version( file->TargetPath )))
2083 TRACE("new %s old %s\n", debugstr_w(file->Version),
2084 debugstr_w(file_version));
2085 /* FIXME: seems like a bad way to compare version numbers */
2086 if (lstrcmpiW(file_version, file->Version)<0)
2088 file->state = msifs_overwrite;
2089 comp->Cost += file->FileSize;
2090 comp->Installed = INSTALLSTATE_INCOMPLETE;
2092 else
2093 file->state = msifs_present;
2094 msi_free( file_version );
2096 else
2097 file->state = msifs_present;
2100 return ERROR_SUCCESS;
2104 * A lot is done in this function aside from just the costing.
2105 * The costing needs to be implemented at some point but for now I am going
2106 * to focus on the directory building
2109 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2111 static const WCHAR ExecSeqQuery[] =
2112 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2113 '`','D','i','r','e','c','t','o','r','y','`',0};
2114 static const WCHAR ConditionQuery[] =
2115 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2116 '`','C','o','n','d','i','t','i','o','n','`',0};
2117 static const WCHAR szCosting[] =
2118 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2119 static const WCHAR szlevel[] =
2120 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2121 static const WCHAR szOne[] = { '1', 0 };
2122 MSICOMPONENT *comp;
2123 UINT rc;
2124 MSIQUERY * view;
2125 LPWSTR level;
2127 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2128 return ERROR_SUCCESS;
2130 TRACE("Building Directory properties\n");
2132 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2133 if (rc == ERROR_SUCCESS)
2135 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2136 package);
2137 msiobj_release(&view->hdr);
2140 /* read components states from the registry */
2141 ACTION_GetComponentInstallStates(package);
2143 TRACE("File calculations\n");
2144 msi_check_file_install_states( package );
2146 TRACE("Evaluating Condition Table\n");
2148 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2149 if (rc == ERROR_SUCCESS)
2151 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2152 package);
2153 msiobj_release(&view->hdr);
2156 TRACE("Enabling or Disabling Components\n");
2157 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2159 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2161 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2162 comp->Enabled = FALSE;
2166 MSI_SetPropertyW(package,szCosting,szOne);
2167 /* set default run level if not set */
2168 level = msi_dup_property( package, szlevel );
2169 if (!level)
2170 MSI_SetPropertyW(package,szlevel, szOne);
2171 msi_free(level);
2173 ACTION_UpdateFeatureInstallStates(package);
2175 return MSI_SetFeatureStates(package);
2178 /* OK this value is "interpreted" and then formatted based on the
2179 first few characters */
2180 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2181 DWORD *size)
2183 LPSTR data = NULL;
2185 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2187 if (value[1]=='x')
2189 LPWSTR ptr;
2190 CHAR byte[5];
2191 LPWSTR deformated = NULL;
2192 int count;
2194 deformat_string(package, &value[2], &deformated);
2196 /* binary value type */
2197 ptr = deformated;
2198 *type = REG_BINARY;
2199 if (strlenW(ptr)%2)
2200 *size = (strlenW(ptr)/2)+1;
2201 else
2202 *size = strlenW(ptr)/2;
2204 data = msi_alloc(*size);
2206 byte[0] = '0';
2207 byte[1] = 'x';
2208 byte[4] = 0;
2209 count = 0;
2210 /* if uneven pad with a zero in front */
2211 if (strlenW(ptr)%2)
2213 byte[2]= '0';
2214 byte[3]= *ptr;
2215 ptr++;
2216 data[count] = (BYTE)strtol(byte,NULL,0);
2217 count ++;
2218 TRACE("Uneven byte count\n");
2220 while (*ptr)
2222 byte[2]= *ptr;
2223 ptr++;
2224 byte[3]= *ptr;
2225 ptr++;
2226 data[count] = (BYTE)strtol(byte,NULL,0);
2227 count ++;
2229 msi_free(deformated);
2231 TRACE("Data %i bytes(%i)\n",*size,count);
2233 else
2235 LPWSTR deformated;
2236 LPWSTR p;
2237 DWORD d = 0;
2238 deformat_string(package, &value[1], &deformated);
2240 *type=REG_DWORD;
2241 *size = sizeof(DWORD);
2242 data = msi_alloc(*size);
2243 p = deformated;
2244 if (*p == '-')
2245 p++;
2246 while (*p)
2248 if ( (*p < '0') || (*p > '9') )
2249 break;
2250 d *= 10;
2251 d += (*p - '0');
2252 p++;
2254 if (deformated[0] == '-')
2255 d = -d;
2256 *(LPDWORD)data = d;
2257 TRACE("DWORD %i\n",*(LPDWORD)data);
2259 msi_free(deformated);
2262 else
2264 static const WCHAR szMulti[] = {'[','~',']',0};
2265 LPCWSTR ptr;
2266 *type=REG_SZ;
2268 if (value[0]=='#')
2270 if (value[1]=='%')
2272 ptr = &value[2];
2273 *type=REG_EXPAND_SZ;
2275 else
2276 ptr = &value[1];
2278 else
2279 ptr=value;
2281 if (strstrW(value,szMulti))
2282 *type = REG_MULTI_SZ;
2284 /* remove initial delimiter */
2285 if (!strncmpW(value, szMulti, 3))
2286 ptr = value + 3;
2288 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2290 /* add double NULL terminator */
2291 if (*type == REG_MULTI_SZ)
2293 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2294 data = msi_realloc_zero(data, *size);
2297 return data;
2300 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2302 MSIPACKAGE *package = (MSIPACKAGE*)param;
2303 static const WCHAR szHCR[] =
2304 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2305 'R','O','O','T','\\',0};
2306 static const WCHAR szHCU[] =
2307 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2308 'U','S','E','R','\\',0};
2309 static const WCHAR szHLM[] =
2310 {'H','K','E','Y','_','L','O','C','A','L','_',
2311 'M','A','C','H','I','N','E','\\',0};
2312 static const WCHAR szHU[] =
2313 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2315 LPSTR value_data = NULL;
2316 HKEY root_key, hkey;
2317 DWORD type,size;
2318 LPWSTR deformated;
2319 LPCWSTR szRoot, component, name, key, value;
2320 MSICOMPONENT *comp;
2321 MSIRECORD * uirow;
2322 LPWSTR uikey;
2323 INT root;
2324 BOOL check_first = FALSE;
2325 UINT rc;
2327 ui_progress(package,2,0,0,0);
2329 value = NULL;
2330 key = NULL;
2331 uikey = NULL;
2332 name = NULL;
2334 component = MSI_RecordGetString(row, 6);
2335 comp = get_loaded_component(package,component);
2336 if (!comp)
2337 return ERROR_SUCCESS;
2339 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2341 TRACE("Skipping write due to disabled component %s\n",
2342 debugstr_w(component));
2344 comp->Action = comp->Installed;
2346 return ERROR_SUCCESS;
2349 comp->Action = INSTALLSTATE_LOCAL;
2351 name = MSI_RecordGetString(row, 4);
2352 if( MSI_RecordIsNull(row,5) && name )
2354 /* null values can have special meanings */
2355 if (name[0]=='-' && name[1] == 0)
2356 return ERROR_SUCCESS;
2357 else if ((name[0]=='+' && name[1] == 0) ||
2358 (name[0] == '*' && name[1] == 0))
2359 name = NULL;
2360 check_first = TRUE;
2363 root = MSI_RecordGetInteger(row,2);
2364 key = MSI_RecordGetString(row, 3);
2366 /* get the root key */
2367 switch (root)
2369 case -1:
2371 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2372 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2373 if (all_users && all_users[0] == '1')
2375 root_key = HKEY_LOCAL_MACHINE;
2376 szRoot = szHLM;
2378 else
2380 root_key = HKEY_CURRENT_USER;
2381 szRoot = szHCU;
2383 msi_free(all_users);
2385 break;
2386 case 0: root_key = HKEY_CLASSES_ROOT;
2387 szRoot = szHCR;
2388 break;
2389 case 1: root_key = HKEY_CURRENT_USER;
2390 szRoot = szHCU;
2391 break;
2392 case 2: root_key = HKEY_LOCAL_MACHINE;
2393 szRoot = szHLM;
2394 break;
2395 case 3: root_key = HKEY_USERS;
2396 szRoot = szHU;
2397 break;
2398 default:
2399 ERR("Unknown root %i\n",root);
2400 root_key=NULL;
2401 szRoot = NULL;
2402 break;
2404 if (!root_key)
2405 return ERROR_SUCCESS;
2407 deformat_string(package, key , &deformated);
2408 size = strlenW(deformated) + strlenW(szRoot) + 1;
2409 uikey = msi_alloc(size*sizeof(WCHAR));
2410 strcpyW(uikey,szRoot);
2411 strcatW(uikey,deformated);
2413 if (RegCreateKeyW( root_key, deformated, &hkey))
2415 ERR("Could not create key %s\n",debugstr_w(deformated));
2416 msi_free(deformated);
2417 msi_free(uikey);
2418 return ERROR_SUCCESS;
2420 msi_free(deformated);
2422 value = MSI_RecordGetString(row,5);
2423 if (value)
2424 value_data = parse_value(package, value, &type, &size);
2425 else
2427 static const WCHAR szEmpty[] = {0};
2428 value_data = (LPSTR)strdupW(szEmpty);
2429 size = 0;
2430 type = REG_SZ;
2433 deformat_string(package, name, &deformated);
2435 if (!check_first)
2437 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2438 debugstr_w(uikey));
2439 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2441 else
2443 DWORD sz = 0;
2444 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2445 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2447 TRACE("value %s of %s checked already exists\n",
2448 debugstr_w(deformated), debugstr_w(uikey));
2450 else
2452 TRACE("Checked and setting value %s of %s\n",
2453 debugstr_w(deformated), debugstr_w(uikey));
2454 if (deformated || size)
2455 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2458 RegCloseKey(hkey);
2460 uirow = MSI_CreateRecord(3);
2461 MSI_RecordSetStringW(uirow,2,deformated);
2462 MSI_RecordSetStringW(uirow,1,uikey);
2464 if (type == REG_SZ)
2465 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2466 else
2467 MSI_RecordSetStringW(uirow,3,value);
2469 ui_actiondata(package,szWriteRegistryValues,uirow);
2470 msiobj_release( &uirow->hdr );
2472 msi_free(value_data);
2473 msi_free(deformated);
2474 msi_free(uikey);
2476 return ERROR_SUCCESS;
2479 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2481 UINT rc;
2482 MSIQUERY * view;
2483 static const WCHAR ExecSeqQuery[] =
2484 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2485 '`','R','e','g','i','s','t','r','y','`',0 };
2487 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2488 if (rc != ERROR_SUCCESS)
2489 return ERROR_SUCCESS;
2491 /* increment progress bar each time action data is sent */
2492 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2494 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2496 msiobj_release(&view->hdr);
2497 return rc;
2500 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2502 package->script->CurrentlyScripting = TRUE;
2504 return ERROR_SUCCESS;
2508 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2510 MSICOMPONENT *comp;
2511 DWORD progress = 0;
2512 DWORD total = 0;
2513 static const WCHAR q1[]=
2514 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2515 '`','R','e','g','i','s','t','r','y','`',0};
2516 UINT rc;
2517 MSIQUERY * view;
2518 MSIFEATURE *feature;
2519 MSIFILE *file;
2521 TRACE("InstallValidate\n");
2523 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2524 if (rc == ERROR_SUCCESS)
2526 MSI_IterateRecords( view, &progress, NULL, package );
2527 msiobj_release( &view->hdr );
2528 total += progress * REG_PROGRESS_VALUE;
2531 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2532 total += COMPONENT_PROGRESS_VALUE;
2534 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2535 total += file->FileSize;
2537 ui_progress(package,0,total,0,0);
2539 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2541 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2542 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2543 feature->ActionRequest);
2546 return ERROR_SUCCESS;
2549 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2551 MSIPACKAGE* package = (MSIPACKAGE*)param;
2552 LPCWSTR cond = NULL;
2553 LPCWSTR message = NULL;
2554 UINT r;
2556 static const WCHAR title[]=
2557 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2559 cond = MSI_RecordGetString(row,1);
2561 r = MSI_EvaluateConditionW(package,cond);
2562 if (r == MSICONDITION_FALSE)
2564 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2566 LPWSTR deformated;
2567 message = MSI_RecordGetString(row,2);
2568 deformat_string(package,message,&deformated);
2569 MessageBoxW(NULL,deformated,title,MB_OK);
2570 msi_free(deformated);
2573 return ERROR_INSTALL_FAILURE;
2576 return ERROR_SUCCESS;
2579 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2581 UINT rc;
2582 MSIQUERY * view = NULL;
2583 static const WCHAR ExecSeqQuery[] =
2584 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2585 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2587 TRACE("Checking launch conditions\n");
2589 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2590 if (rc != ERROR_SUCCESS)
2591 return ERROR_SUCCESS;
2593 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2594 msiobj_release(&view->hdr);
2596 return rc;
2599 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2602 if (!cmp->KeyPath)
2603 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2605 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2607 MSIRECORD * row = 0;
2608 UINT root,len;
2609 LPWSTR deformated,buffer,deformated_name;
2610 LPCWSTR key,name;
2611 static const WCHAR ExecSeqQuery[] =
2612 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2613 '`','R','e','g','i','s','t','r','y','`',' ',
2614 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2615 ' ','=',' ' ,'\'','%','s','\'',0 };
2616 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2617 static const WCHAR fmt2[]=
2618 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2620 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2621 if (!row)
2622 return NULL;
2624 root = MSI_RecordGetInteger(row,2);
2625 key = MSI_RecordGetString(row, 3);
2626 name = MSI_RecordGetString(row, 4);
2627 deformat_string(package, key , &deformated);
2628 deformat_string(package, name, &deformated_name);
2630 len = strlenW(deformated) + 6;
2631 if (deformated_name)
2632 len+=strlenW(deformated_name);
2634 buffer = msi_alloc( len *sizeof(WCHAR));
2636 if (deformated_name)
2637 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2638 else
2639 sprintfW(buffer,fmt,root,deformated);
2641 msi_free(deformated);
2642 msi_free(deformated_name);
2643 msiobj_release(&row->hdr);
2645 return buffer;
2647 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2649 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2650 return NULL;
2652 else
2654 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2656 if (file)
2657 return strdupW( file->TargetPath );
2659 return NULL;
2662 static HKEY openSharedDLLsKey(void)
2664 HKEY hkey=0;
2665 static const WCHAR path[] =
2666 {'S','o','f','t','w','a','r','e','\\',
2667 'M','i','c','r','o','s','o','f','t','\\',
2668 'W','i','n','d','o','w','s','\\',
2669 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2670 'S','h','a','r','e','d','D','L','L','s',0};
2672 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2673 return hkey;
2676 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2678 HKEY hkey;
2679 DWORD count=0;
2680 DWORD type;
2681 DWORD sz = sizeof(count);
2682 DWORD rc;
2684 hkey = openSharedDLLsKey();
2685 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2686 if (rc != ERROR_SUCCESS)
2687 count = 0;
2688 RegCloseKey(hkey);
2689 return count;
2692 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2694 HKEY hkey;
2696 hkey = openSharedDLLsKey();
2697 if (count > 0)
2698 msi_reg_set_val_dword( hkey, path, count );
2699 else
2700 RegDeleteValueW(hkey,path);
2701 RegCloseKey(hkey);
2702 return count;
2706 * Return TRUE if the count should be written out and FALSE if not
2708 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2710 MSIFEATURE *feature;
2711 INT count = 0;
2712 BOOL write = FALSE;
2714 /* only refcount DLLs */
2715 if (comp->KeyPath == NULL ||
2716 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2717 comp->Attributes & msidbComponentAttributesODBCDataSource)
2718 write = FALSE;
2719 else
2721 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2722 write = (count > 0);
2724 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2725 write = TRUE;
2728 /* increment counts */
2729 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2731 ComponentList *cl;
2733 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2734 continue;
2736 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2738 if ( cl->component == comp )
2739 count++;
2743 /* decrement counts */
2744 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2746 ComponentList *cl;
2748 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2749 continue;
2751 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2753 if ( cl->component == comp )
2754 count--;
2758 /* ref count all the files in the component */
2759 if (write)
2761 MSIFILE *file;
2763 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2765 if (file->Component == comp)
2766 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2770 /* add a count for permanent */
2771 if (comp->Attributes & msidbComponentAttributesPermanent)
2772 count ++;
2774 comp->RefCount = count;
2776 if (write)
2777 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2781 * Ok further analysis makes me think that this work is
2782 * actually done in the PublishComponents and PublishFeatures
2783 * step, and not here. It appears like the keypath and all that is
2784 * resolved in this step, however actually written in the Publish steps.
2785 * But we will leave it here for now because it is unclear
2787 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2789 WCHAR squished_pc[GUID_SIZE];
2790 WCHAR squished_cc[GUID_SIZE];
2791 UINT rc;
2792 MSICOMPONENT *comp;
2793 HKEY hkey=0,hkey2=0;
2795 TRACE("\n");
2797 /* writes the Component and Features values to the registry */
2799 rc = MSIREG_OpenComponents(&hkey);
2800 if (rc != ERROR_SUCCESS)
2801 return rc;
2803 squash_guid(package->ProductCode,squished_pc);
2804 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2806 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2808 MSIRECORD * uirow;
2810 ui_progress(package,2,0,0,0);
2811 if (!comp->ComponentId)
2812 continue;
2814 squash_guid(comp->ComponentId,squished_cc);
2816 msi_free(comp->FullKeypath);
2817 comp->FullKeypath = resolve_keypath( package, comp );
2819 /* do the refcounting */
2820 ACTION_RefCountComponent( package, comp );
2822 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2823 debugstr_w(comp->Component),
2824 debugstr_w(squished_cc),
2825 debugstr_w(comp->FullKeypath),
2826 comp->RefCount);
2828 * Write the keypath out if the component is to be registered
2829 * and delete the key if the component is to be unregistered
2831 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2833 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2834 if (rc != ERROR_SUCCESS)
2835 continue;
2837 if (!comp->FullKeypath)
2838 continue;
2840 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2842 if (comp->Attributes & msidbComponentAttributesPermanent)
2844 static const WCHAR szPermKey[] =
2845 { '0','0','0','0','0','0','0','0','0','0','0','0',
2846 '0','0','0','0','0','0','0','0','0','0','0','0',
2847 '0','0','0','0','0','0','0','0',0 };
2849 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2852 RegCloseKey(hkey2);
2854 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, &hkey2, TRUE);
2855 if (rc != ERROR_SUCCESS)
2856 continue;
2858 msi_reg_set_val_str(hkey2, squished_pc, comp->FullKeypath);
2859 RegCloseKey(hkey2);
2861 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2863 DWORD res;
2865 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2866 if (rc != ERROR_SUCCESS)
2867 continue;
2869 RegDeleteValueW(hkey2,squished_pc);
2871 /* if the key is empty delete it */
2872 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2873 RegCloseKey(hkey2);
2874 if (res == ERROR_NO_MORE_ITEMS)
2875 RegDeleteKeyW(hkey,squished_cc);
2877 MSIREG_DeleteUserDataComponentKey(comp->ComponentId);
2880 /* UI stuff */
2881 uirow = MSI_CreateRecord(3);
2882 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2883 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2884 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2885 ui_actiondata(package,szProcessComponents,uirow);
2886 msiobj_release( &uirow->hdr );
2888 RegCloseKey(hkey);
2889 return rc;
2892 typedef struct {
2893 CLSID clsid;
2894 LPWSTR source;
2896 LPWSTR path;
2897 ITypeLib *ptLib;
2898 } typelib_struct;
2900 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2901 LPWSTR lpszName, LONG_PTR lParam)
2903 TLIBATTR *attr;
2904 typelib_struct *tl_struct = (typelib_struct*) lParam;
2905 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2906 int sz;
2907 HRESULT res;
2909 if (!IS_INTRESOURCE(lpszName))
2911 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2912 return TRUE;
2915 sz = strlenW(tl_struct->source)+4;
2916 sz *= sizeof(WCHAR);
2918 if ((INT_PTR)lpszName == 1)
2919 tl_struct->path = strdupW(tl_struct->source);
2920 else
2922 tl_struct->path = msi_alloc(sz);
2923 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2926 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2927 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2928 if (!SUCCEEDED(res))
2930 msi_free(tl_struct->path);
2931 tl_struct->path = NULL;
2933 return TRUE;
2936 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2937 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2939 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2940 return FALSE;
2943 msi_free(tl_struct->path);
2944 tl_struct->path = NULL;
2946 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2947 ITypeLib_Release(tl_struct->ptLib);
2949 return TRUE;
2952 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2954 MSIPACKAGE* package = (MSIPACKAGE*)param;
2955 LPCWSTR component;
2956 MSICOMPONENT *comp;
2957 MSIFILE *file;
2958 typelib_struct tl_struct;
2959 HMODULE module;
2960 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2962 component = MSI_RecordGetString(row,3);
2963 comp = get_loaded_component(package,component);
2964 if (!comp)
2965 return ERROR_SUCCESS;
2967 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2969 TRACE("Skipping typelib reg due to disabled component\n");
2971 comp->Action = comp->Installed;
2973 return ERROR_SUCCESS;
2976 comp->Action = INSTALLSTATE_LOCAL;
2978 file = get_loaded_file( package, comp->KeyPath );
2979 if (!file)
2980 return ERROR_SUCCESS;
2982 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2983 if (module)
2985 LPCWSTR guid;
2986 guid = MSI_RecordGetString(row,1);
2987 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2988 tl_struct.source = strdupW( file->TargetPath );
2989 tl_struct.path = NULL;
2991 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2992 (LONG_PTR)&tl_struct);
2994 if (tl_struct.path)
2996 LPWSTR help = NULL;
2997 LPCWSTR helpid;
2998 HRESULT res;
3000 helpid = MSI_RecordGetString(row,6);
3002 if (helpid)
3003 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3004 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3005 msi_free(help);
3007 if (!SUCCEEDED(res))
3008 ERR("Failed to register type library %s\n",
3009 debugstr_w(tl_struct.path));
3010 else
3012 ui_actiondata(package,szRegisterTypeLibraries,row);
3014 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3017 ITypeLib_Release(tl_struct.ptLib);
3018 msi_free(tl_struct.path);
3020 else
3021 ERR("Failed to load type library %s\n",
3022 debugstr_w(tl_struct.source));
3024 FreeLibrary(module);
3025 msi_free(tl_struct.source);
3027 else
3028 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
3030 return ERROR_SUCCESS;
3033 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3036 * OK this is a bit confusing.. I am given a _Component key and I believe
3037 * that the file that is being registered as a type library is the "key file
3038 * of that component" which I interpret to mean "The file in the KeyPath of
3039 * that component".
3041 UINT rc;
3042 MSIQUERY * view;
3043 static const WCHAR Query[] =
3044 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3045 '`','T','y','p','e','L','i','b','`',0};
3047 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3048 if (rc != ERROR_SUCCESS)
3049 return ERROR_SUCCESS;
3051 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3052 msiobj_release(&view->hdr);
3053 return rc;
3056 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3058 MSIPACKAGE *package = (MSIPACKAGE*)param;
3059 LPWSTR target_file, target_folder, filename;
3060 LPCWSTR buffer, extension;
3061 MSICOMPONENT *comp;
3062 static const WCHAR szlnk[]={'.','l','n','k',0};
3063 IShellLinkW *sl = NULL;
3064 IPersistFile *pf = NULL;
3065 HRESULT res;
3067 buffer = MSI_RecordGetString(row,4);
3068 comp = get_loaded_component(package,buffer);
3069 if (!comp)
3070 return ERROR_SUCCESS;
3072 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3074 TRACE("Skipping shortcut creation due to disabled component\n");
3076 comp->Action = comp->Installed;
3078 return ERROR_SUCCESS;
3081 comp->Action = INSTALLSTATE_LOCAL;
3083 ui_actiondata(package,szCreateShortcuts,row);
3085 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3086 &IID_IShellLinkW, (LPVOID *) &sl );
3088 if (FAILED( res ))
3090 ERR("CLSID_ShellLink not available\n");
3091 goto err;
3094 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3095 if (FAILED( res ))
3097 ERR("QueryInterface(IID_IPersistFile) failed\n");
3098 goto err;
3101 buffer = MSI_RecordGetString(row,2);
3102 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3104 /* may be needed because of a bug somewhere else */
3105 create_full_pathW(target_folder);
3107 filename = msi_dup_record_field( row, 3 );
3108 reduce_to_longfilename(filename);
3110 extension = strchrW(filename,'.');
3111 if (!extension || strcmpiW(extension,szlnk))
3113 int len = strlenW(filename);
3114 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3115 memcpy(filename + len, szlnk, sizeof(szlnk));
3117 target_file = build_directory_name(2, target_folder, filename);
3118 msi_free(target_folder);
3119 msi_free(filename);
3121 buffer = MSI_RecordGetString(row,5);
3122 if (strchrW(buffer,'['))
3124 LPWSTR deformated;
3125 deformat_string(package,buffer,&deformated);
3126 IShellLinkW_SetPath(sl,deformated);
3127 msi_free(deformated);
3129 else
3131 FIXME("poorly handled shortcut format, advertised shortcut\n");
3132 IShellLinkW_SetPath(sl,comp->FullKeypath);
3135 if (!MSI_RecordIsNull(row,6))
3137 LPWSTR deformated;
3138 buffer = MSI_RecordGetString(row,6);
3139 deformat_string(package,buffer,&deformated);
3140 IShellLinkW_SetArguments(sl,deformated);
3141 msi_free(deformated);
3144 if (!MSI_RecordIsNull(row,7))
3146 buffer = MSI_RecordGetString(row,7);
3147 IShellLinkW_SetDescription(sl,buffer);
3150 if (!MSI_RecordIsNull(row,8))
3151 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3153 if (!MSI_RecordIsNull(row,9))
3155 LPWSTR Path;
3156 INT index;
3158 buffer = MSI_RecordGetString(row,9);
3160 Path = build_icon_path(package,buffer);
3161 index = MSI_RecordGetInteger(row,10);
3163 /* no value means 0 */
3164 if (index == MSI_NULL_INTEGER)
3165 index = 0;
3167 IShellLinkW_SetIconLocation(sl,Path,index);
3168 msi_free(Path);
3171 if (!MSI_RecordIsNull(row,11))
3172 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3174 if (!MSI_RecordIsNull(row,12))
3176 LPWSTR Path;
3177 buffer = MSI_RecordGetString(row,12);
3178 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3179 if (Path)
3180 IShellLinkW_SetWorkingDirectory(sl,Path);
3181 msi_free(Path);
3184 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3185 IPersistFile_Save(pf,target_file,FALSE);
3187 msi_free(target_file);
3189 err:
3190 if (pf)
3191 IPersistFile_Release( pf );
3192 if (sl)
3193 IShellLinkW_Release( sl );
3195 return ERROR_SUCCESS;
3198 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3200 UINT rc;
3201 HRESULT res;
3202 MSIQUERY * view;
3203 static const WCHAR Query[] =
3204 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3205 '`','S','h','o','r','t','c','u','t','`',0};
3207 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3208 if (rc != ERROR_SUCCESS)
3209 return ERROR_SUCCESS;
3211 res = CoInitialize( NULL );
3212 if (FAILED (res))
3214 ERR("CoInitialize failed\n");
3215 return ERROR_FUNCTION_FAILED;
3218 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3219 msiobj_release(&view->hdr);
3221 CoUninitialize();
3223 return rc;
3226 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3228 MSIPACKAGE* package = (MSIPACKAGE*)param;
3229 HANDLE the_file;
3230 LPWSTR FilePath;
3231 LPCWSTR FileName;
3232 CHAR buffer[1024];
3233 DWORD sz;
3234 UINT rc;
3235 MSIRECORD *uirow;
3237 FileName = MSI_RecordGetString(row,1);
3238 if (!FileName)
3240 ERR("Unable to get FileName\n");
3241 return ERROR_SUCCESS;
3244 FilePath = build_icon_path(package,FileName);
3246 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3248 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3249 FILE_ATTRIBUTE_NORMAL, NULL);
3251 if (the_file == INVALID_HANDLE_VALUE)
3253 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3254 msi_free(FilePath);
3255 return ERROR_SUCCESS;
3260 DWORD write;
3261 sz = 1024;
3262 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3263 if (rc != ERROR_SUCCESS)
3265 ERR("Failed to get stream\n");
3266 CloseHandle(the_file);
3267 DeleteFileW(FilePath);
3268 break;
3270 WriteFile(the_file,buffer,sz,&write,NULL);
3271 } while (sz == 1024);
3273 msi_free(FilePath);
3275 CloseHandle(the_file);
3277 uirow = MSI_CreateRecord(1);
3278 MSI_RecordSetStringW(uirow,1,FileName);
3279 ui_actiondata(package,szPublishProduct,uirow);
3280 msiobj_release( &uirow->hdr );
3282 return ERROR_SUCCESS;
3285 static BOOL msi_check_publish(MSIPACKAGE *package)
3287 MSIFEATURE *feature;
3289 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3291 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3292 return TRUE;
3295 return FALSE;
3299 * 99% of the work done here is only done for
3300 * advertised installs. However this is where the
3301 * Icon table is processed and written out
3302 * so that is what I am going to do here.
3304 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3306 UINT rc;
3307 LPWSTR packname;
3308 MSIQUERY * view;
3309 MSISOURCELISTINFO *info;
3310 MSIMEDIADISK *disk;
3311 static const WCHAR Query[]=
3312 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3313 '`','I','c','o','n','`',0};
3314 /* for registry stuff */
3315 HKEY hkey=0;
3316 HKEY hukey=0;
3317 HKEY hudkey=0, props=0;
3318 HKEY source;
3319 static const WCHAR szProductLanguage[] =
3320 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3321 static const WCHAR szARPProductIcon[] =
3322 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3323 static const WCHAR szProductVersion[] =
3324 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3325 static const WCHAR szSourceList[] =
3326 {'S','o','u','r','c','e','L','i','s','t',0};
3327 static const WCHAR szEmpty[] = {0};
3328 DWORD langid;
3329 LPWSTR buffer;
3330 DWORD size;
3331 MSIHANDLE hDb, hSumInfo;
3333 /* FIXME: also need to publish if the product is in advertise mode */
3334 if (!msi_check_publish(package))
3335 return ERROR_SUCCESS;
3337 /* write out icon files */
3339 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3340 if (rc == ERROR_SUCCESS)
3342 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3343 msiobj_release(&view->hdr);
3346 /* ok there is a lot more done here but i need to figure out what */
3348 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3350 rc = MSIREG_OpenLocalClassesProductKey(package->ProductCode, &hukey, TRUE);
3351 if (rc != ERROR_SUCCESS)
3352 goto end;
3354 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
3355 if (rc != ERROR_SUCCESS)
3356 goto end;
3358 else
3360 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3361 if (rc != ERROR_SUCCESS)
3362 goto end;
3364 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3365 if (rc != ERROR_SUCCESS)
3366 goto end;
3368 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
3369 if (rc != ERROR_SUCCESS)
3370 goto end;
3373 rc = RegCreateKeyW(hukey, szSourceList, &source);
3374 if (rc != ERROR_SUCCESS)
3375 goto end;
3377 RegCloseKey(source);
3379 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3380 if (rc != ERROR_SUCCESS)
3381 goto end;
3383 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3384 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3385 msi_free(buffer);
3387 langid = msi_get_property_int( package, szProductLanguage, 0 );
3388 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_LANGUAGEW, langid );
3390 packname = strrchrW( package->PackagePath, '\\' ) + 1;
3391 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGENAMEW, packname );
3393 /* FIXME */
3394 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0 );
3395 msi_reg_set_val_dword( props, INSTALLPROPERTY_INSTANCETYPEW, 0 );
3397 buffer = msi_dup_property( package, szARPProductIcon );
3398 if (buffer)
3400 LPWSTR path = build_icon_path(package,buffer);
3401 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3402 msi_free( path );
3404 msi_free(buffer);
3406 buffer = msi_dup_property( package, szProductVersion );
3407 if (buffer)
3409 DWORD verdword = msi_version_str_to_dword(buffer);
3410 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_VERSIONW, verdword );
3412 msi_free(buffer);
3414 buffer = strrchrW( package->PackagePath, '\\') + 1;
3415 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
3416 package->Context, MSICODE_PRODUCT,
3417 INSTALLPROPERTY_PACKAGENAMEW, buffer );
3418 if (rc != ERROR_SUCCESS)
3419 goto end;
3421 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
3422 package->Context, MSICODE_PRODUCT,
3423 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty );
3424 if (rc != ERROR_SUCCESS)
3425 goto end;
3427 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
3428 package->Context, MSICODE_PRODUCT,
3429 INSTALLPROPERTY_DISKPROMPTW, szEmpty );
3430 if (rc != ERROR_SUCCESS)
3431 goto end;
3433 /* FIXME: Need to write more keys to the user registry */
3435 hDb= alloc_msihandle( &package->db->hdr );
3436 if (!hDb) {
3437 rc = ERROR_NOT_ENOUGH_MEMORY;
3438 goto end;
3440 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3441 MsiCloseHandle(hDb);
3442 if (rc == ERROR_SUCCESS)
3444 WCHAR guidbuffer[0x200];
3445 size = 0x200;
3446 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3447 guidbuffer, &size);
3448 if (rc == ERROR_SUCCESS)
3450 /* for now we only care about the first guid */
3451 LPWSTR ptr = strchrW(guidbuffer,';');
3452 if (ptr) *ptr = 0;
3453 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, guidbuffer );
3455 else
3457 ERR("Unable to query Revision_Number...\n");
3458 rc = ERROR_SUCCESS;
3460 MsiCloseHandle(hSumInfo);
3462 else
3464 ERR("Unable to open Summary Information\n");
3465 rc = ERROR_SUCCESS;
3468 /* publish the SourceList info */
3469 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3471 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3472 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3473 info->options, info->value);
3474 else
3475 MsiSourceListSetInfoW(package->ProductCode, NULL,
3476 info->context, info->options,
3477 info->property, info->value);
3480 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3482 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3483 disk->context, disk->options,
3484 disk->disk_id, disk->volume_label, disk->disk_prompt);
3487 end:
3488 RegCloseKey(hkey);
3489 RegCloseKey(hukey);
3490 RegCloseKey(hudkey);
3491 RegCloseKey(props);
3493 return rc;
3496 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3498 MSIPACKAGE *package = (MSIPACKAGE*)param;
3499 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3500 LPWSTR deformated_section, deformated_key, deformated_value;
3501 LPWSTR folder, fullname = NULL;
3502 MSIRECORD * uirow;
3503 INT action;
3504 MSICOMPONENT *comp;
3505 static const WCHAR szWindowsFolder[] =
3506 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3508 component = MSI_RecordGetString(row, 8);
3509 comp = get_loaded_component(package,component);
3511 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3513 TRACE("Skipping ini file due to disabled component %s\n",
3514 debugstr_w(component));
3516 comp->Action = comp->Installed;
3518 return ERROR_SUCCESS;
3521 comp->Action = INSTALLSTATE_LOCAL;
3523 identifier = MSI_RecordGetString(row,1);
3524 filename = MSI_RecordGetString(row,2);
3525 dirproperty = MSI_RecordGetString(row,3);
3526 section = MSI_RecordGetString(row,4);
3527 key = MSI_RecordGetString(row,5);
3528 value = MSI_RecordGetString(row,6);
3529 action = MSI_RecordGetInteger(row,7);
3531 deformat_string(package,section,&deformated_section);
3532 deformat_string(package,key,&deformated_key);
3533 deformat_string(package,value,&deformated_value);
3535 if (dirproperty)
3537 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3538 if (!folder)
3539 folder = msi_dup_property( package, dirproperty );
3541 else
3542 folder = msi_dup_property( package, szWindowsFolder );
3544 if (!folder)
3546 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3547 goto cleanup;
3550 fullname = build_directory_name(2, folder, filename);
3552 if (action == 0)
3554 TRACE("Adding value %s to section %s in %s\n",
3555 debugstr_w(deformated_key), debugstr_w(deformated_section),
3556 debugstr_w(fullname));
3557 WritePrivateProfileStringW(deformated_section, deformated_key,
3558 deformated_value, fullname);
3560 else if (action == 1)
3562 WCHAR returned[10];
3563 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3564 returned, 10, fullname);
3565 if (returned[0] == 0)
3567 TRACE("Adding value %s to section %s in %s\n",
3568 debugstr_w(deformated_key), debugstr_w(deformated_section),
3569 debugstr_w(fullname));
3571 WritePrivateProfileStringW(deformated_section, deformated_key,
3572 deformated_value, fullname);
3575 else if (action == 3)
3576 FIXME("Append to existing section not yet implemented\n");
3578 uirow = MSI_CreateRecord(4);
3579 MSI_RecordSetStringW(uirow,1,identifier);
3580 MSI_RecordSetStringW(uirow,2,deformated_section);
3581 MSI_RecordSetStringW(uirow,3,deformated_key);
3582 MSI_RecordSetStringW(uirow,4,deformated_value);
3583 ui_actiondata(package,szWriteIniValues,uirow);
3584 msiobj_release( &uirow->hdr );
3585 cleanup:
3586 msi_free(fullname);
3587 msi_free(folder);
3588 msi_free(deformated_key);
3589 msi_free(deformated_value);
3590 msi_free(deformated_section);
3591 return ERROR_SUCCESS;
3594 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3596 UINT rc;
3597 MSIQUERY * view;
3598 static const WCHAR ExecSeqQuery[] =
3599 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3600 '`','I','n','i','F','i','l','e','`',0};
3602 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3603 if (rc != ERROR_SUCCESS)
3605 TRACE("no IniFile table\n");
3606 return ERROR_SUCCESS;
3609 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3610 msiobj_release(&view->hdr);
3611 return rc;
3614 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3616 MSIPACKAGE *package = (MSIPACKAGE*)param;
3617 LPCWSTR filename;
3618 LPWSTR FullName;
3619 MSIFILE *file;
3620 DWORD len;
3621 static const WCHAR ExeStr[] =
3622 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3623 static const WCHAR close[] = {'\"',0};
3624 STARTUPINFOW si;
3625 PROCESS_INFORMATION info;
3626 BOOL brc;
3627 MSIRECORD *uirow;
3628 LPWSTR uipath, p;
3630 memset(&si,0,sizeof(STARTUPINFOW));
3632 filename = MSI_RecordGetString(row,1);
3633 file = get_loaded_file( package, filename );
3635 if (!file)
3637 ERR("Unable to find file id %s\n",debugstr_w(filename));
3638 return ERROR_SUCCESS;
3641 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3643 FullName = msi_alloc(len*sizeof(WCHAR));
3644 strcpyW(FullName,ExeStr);
3645 strcatW( FullName, file->TargetPath );
3646 strcatW(FullName,close);
3648 TRACE("Registering %s\n",debugstr_w(FullName));
3649 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3650 &si, &info);
3652 if (brc)
3653 msi_dialog_check_messages(info.hProcess);
3655 msi_free(FullName);
3657 /* the UI chunk */
3658 uirow = MSI_CreateRecord( 2 );
3659 uipath = strdupW( file->TargetPath );
3660 p = strrchrW(uipath,'\\');
3661 if (p)
3662 p[0]=0;
3663 MSI_RecordSetStringW( uirow, 1, &p[1] );
3664 MSI_RecordSetStringW( uirow, 2, uipath);
3665 ui_actiondata( package, szSelfRegModules, uirow);
3666 msiobj_release( &uirow->hdr );
3667 msi_free( uipath );
3668 /* FIXME: call ui_progress? */
3670 return ERROR_SUCCESS;
3673 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3675 UINT rc;
3676 MSIQUERY * view;
3677 static const WCHAR ExecSeqQuery[] =
3678 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3679 '`','S','e','l','f','R','e','g','`',0};
3681 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3682 if (rc != ERROR_SUCCESS)
3684 TRACE("no SelfReg table\n");
3685 return ERROR_SUCCESS;
3688 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3689 msiobj_release(&view->hdr);
3691 return ERROR_SUCCESS;
3694 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3696 MSIFEATURE *feature;
3697 UINT rc;
3698 HKEY hkey=0;
3699 HKEY hukey=0;
3700 HKEY userdata=0;
3702 if (!msi_check_publish(package))
3703 return ERROR_SUCCESS;
3705 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3706 if (rc != ERROR_SUCCESS)
3707 goto end;
3709 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3710 if (rc != ERROR_SUCCESS)
3711 goto end;
3713 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &userdata, TRUE);
3714 if (rc != ERROR_SUCCESS)
3715 goto end;
3717 /* here the guids are base 85 encoded */
3718 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3720 ComponentList *cl;
3721 LPWSTR data = NULL;
3722 GUID clsid;
3723 INT size;
3724 BOOL absent = FALSE;
3725 MSIRECORD *uirow;
3727 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3728 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3729 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3730 absent = TRUE;
3732 size = 1;
3733 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3735 size += 21;
3737 if (feature->Feature_Parent)
3738 size += strlenW( feature->Feature_Parent )+2;
3740 data = msi_alloc(size * sizeof(WCHAR));
3742 data[0] = 0;
3743 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3745 MSICOMPONENT* component = cl->component;
3746 WCHAR buf[21];
3748 buf[0] = 0;
3749 if (component->ComponentId)
3751 TRACE("From %s\n",debugstr_w(component->ComponentId));
3752 CLSIDFromString(component->ComponentId, &clsid);
3753 encode_base85_guid(&clsid,buf);
3754 TRACE("to %s\n",debugstr_w(buf));
3755 strcatW(data,buf);
3759 if (feature->Feature_Parent)
3761 static const WCHAR sep[] = {'\2',0};
3762 strcatW(data,sep);
3763 strcatW(data,feature->Feature_Parent);
3766 msi_reg_set_val_str( hkey, feature->Feature, data );
3767 msi_reg_set_val_str( userdata, feature->Feature, data );
3768 msi_free(data);
3770 size = 0;
3771 if (feature->Feature_Parent)
3772 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3773 if (!absent)
3775 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3776 (LPBYTE)feature->Feature_Parent,size);
3778 else
3780 size += 2*sizeof(WCHAR);
3781 data = msi_alloc(size);
3782 data[0] = 0x6;
3783 data[1] = 0;
3784 if (feature->Feature_Parent)
3785 strcpyW( &data[1], feature->Feature_Parent );
3786 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3787 (LPBYTE)data,size);
3788 msi_free(data);
3791 /* the UI chunk */
3792 uirow = MSI_CreateRecord( 1 );
3793 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3794 ui_actiondata( package, szPublishFeatures, uirow);
3795 msiobj_release( &uirow->hdr );
3796 /* FIXME: call ui_progress? */
3799 end:
3800 RegCloseKey(hkey);
3801 RegCloseKey(hukey);
3802 return rc;
3805 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3807 UINT r;
3808 HKEY hkey;
3810 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3812 r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
3813 if (r == ERROR_SUCCESS)
3815 RegDeleteValueW(hkey, feature->Feature);
3816 RegCloseKey(hkey);
3819 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
3820 if (r == ERROR_SUCCESS)
3822 RegDeleteValueW(hkey, feature->Feature);
3823 RegCloseKey(hkey);
3826 return ERROR_SUCCESS;
3829 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3831 MSIFEATURE *feature;
3833 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3835 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3836 return FALSE;
3839 return TRUE;
3842 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3844 MSIFEATURE *feature;
3846 if (!msi_check_unpublish(package))
3847 return ERROR_SUCCESS;
3849 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3851 msi_unpublish_feature(package, feature);
3854 return ERROR_SUCCESS;
3857 static UINT msi_get_local_package_name( LPWSTR path )
3859 static const WCHAR szInstaller[] = {
3860 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3861 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3862 DWORD time, len, i;
3863 HANDLE handle;
3865 time = GetTickCount();
3866 GetWindowsDirectoryW( path, MAX_PATH );
3867 lstrcatW( path, szInstaller );
3868 CreateDirectoryW( path, NULL );
3870 len = lstrlenW(path);
3871 for (i=0; i<0x10000; i++)
3873 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3874 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3875 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3876 if (handle != INVALID_HANDLE_VALUE)
3878 CloseHandle(handle);
3879 break;
3881 if (GetLastError() != ERROR_FILE_EXISTS &&
3882 GetLastError() != ERROR_SHARING_VIOLATION)
3883 return ERROR_FUNCTION_FAILED;
3886 return ERROR_SUCCESS;
3889 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3891 WCHAR packagefile[MAX_PATH];
3892 HKEY props;
3893 UINT r;
3895 r = msi_get_local_package_name( packagefile );
3896 if (r != ERROR_SUCCESS)
3897 return r;
3899 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3901 r = CopyFileW( package->db->path, packagefile, FALSE);
3903 if (!r)
3905 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3906 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
3907 return ERROR_FUNCTION_FAILED;
3910 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3912 r = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
3913 if (r != ERROR_SUCCESS)
3914 return r;
3916 msi_reg_set_val_str(props, INSTALLPROPERTY_LOCALPACKAGEW, packagefile);
3917 RegCloseKey(props);
3918 return ERROR_SUCCESS;
3921 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3923 LPWSTR prop, val, key;
3924 static const LPCSTR propval[] = {
3925 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3926 "ARPCONTACT", "Contact",
3927 "ARPCOMMENTS", "Comments",
3928 "ProductName", "DisplayName",
3929 "ProductVersion", "DisplayVersion",
3930 "ARPHELPLINK", "HelpLink",
3931 "ARPHELPTELEPHONE", "HelpTelephone",
3932 "ARPINSTALLLOCATION", "InstallLocation",
3933 "SourceDir", "InstallSource",
3934 "Manufacturer", "Publisher",
3935 "ARPREADME", "Readme",
3936 "ARPSIZE", "Size",
3937 "ARPURLINFOABOUT", "URLInfoAbout",
3938 "ARPURLUPDATEINFO", "URLUpdateInfo",
3939 NULL,
3941 const LPCSTR *p = propval;
3943 while( *p )
3945 prop = strdupAtoW( *p++ );
3946 key = strdupAtoW( *p++ );
3947 val = msi_dup_property( package, prop );
3948 msi_reg_set_val_str( hkey, key, val );
3949 msi_free(val);
3950 msi_free(key);
3951 msi_free(prop);
3953 return ERROR_SUCCESS;
3956 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3958 HKEY hkey=0;
3959 HKEY hudkey=0, props=0;
3960 LPWSTR buffer = NULL;
3961 UINT rc;
3962 DWORD size, langid;
3963 static const WCHAR szWindowsInstaller[] =
3964 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3965 static const WCHAR szUpgradeCode[] =
3966 {'U','p','g','r','a','d','e','C','o','d','e',0};
3967 static const WCHAR modpath_fmt[] =
3968 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3969 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3970 static const WCHAR szModifyPath[] =
3971 {'M','o','d','i','f','y','P','a','t','h',0};
3972 static const WCHAR szUninstallString[] =
3973 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3974 static const WCHAR szEstimatedSize[] =
3975 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3976 static const WCHAR szProductLanguage[] =
3977 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3978 static const WCHAR szProductVersion[] =
3979 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3980 static const WCHAR szProductName[] =
3981 {'P','r','o','d','u','c','t','N','a','m','e',0};
3982 static const WCHAR szDisplayName[] =
3983 {'D','i','s','p','l','a','y','N','a','m','e',0};
3984 static const WCHAR szDisplayVersion[] =
3985 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3986 static const WCHAR szManufacturer[] =
3987 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3989 SYSTEMTIME systime;
3990 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
3991 LPWSTR upgrade_code;
3992 WCHAR szDate[9];
3994 /* FIXME: also need to publish if the product is in advertise mode */
3995 if (!msi_check_publish(package))
3996 return ERROR_SUCCESS;
3998 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3999 if (rc != ERROR_SUCCESS)
4000 return rc;
4002 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4004 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
4005 if (rc != ERROR_SUCCESS)
4006 return rc;
4008 else
4010 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
4011 if (rc != ERROR_SUCCESS)
4012 return rc;
4015 /* dump all the info i can grab */
4016 /* FIXME: Flesh out more information */
4018 msi_write_uninstall_property_vals( package, hkey );
4020 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
4022 msi_make_package_local( package, hkey );
4024 /* do ModifyPath and UninstallString */
4025 size = deformat_string(package,modpath_fmt,&buffer);
4026 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
4027 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
4028 msi_free(buffer);
4030 /* FIXME: Write real Estimated Size when we have it */
4031 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
4033 buffer = msi_dup_property( package, szProductName );
4034 msi_reg_set_val_str( props, szDisplayName, buffer );
4035 msi_free(buffer);
4037 buffer = msi_dup_property( package, cszSourceDir );
4038 msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4039 msi_free(buffer);
4041 buffer = msi_dup_property( package, szManufacturer );
4042 msi_reg_set_val_str( props, INSTALLPROPERTY_PUBLISHERW, buffer);
4043 msi_free(buffer);
4045 GetLocalTime(&systime);
4046 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
4047 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
4048 msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLDATEW, szDate );
4050 langid = msi_get_property_int( package, szProductLanguage, 0 );
4051 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
4053 buffer = msi_dup_property( package, szProductVersion );
4054 msi_reg_set_val_str( props, szDisplayVersion, buffer );
4055 if (buffer)
4057 DWORD verdword = msi_version_str_to_dword(buffer);
4059 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
4060 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONW, verdword );
4061 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
4062 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
4063 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
4064 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
4066 msi_free(buffer);
4068 /* Handle Upgrade Codes */
4069 upgrade_code = msi_dup_property( package, szUpgradeCode );
4070 if (upgrade_code)
4072 HKEY hkey2;
4073 WCHAR squashed[33];
4074 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
4075 squash_guid(package->ProductCode,squashed);
4076 msi_reg_set_val_str( hkey2, squashed, NULL );
4077 RegCloseKey(hkey2);
4078 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
4079 squash_guid(package->ProductCode,squashed);
4080 msi_reg_set_val_str( hkey2, squashed, NULL );
4081 RegCloseKey(hkey2);
4083 msi_free(upgrade_code);
4086 RegCloseKey(hkey);
4088 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
4089 if (rc != ERROR_SUCCESS)
4090 return rc;
4092 RegCloseKey(hudkey);
4094 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
4095 RegCloseKey(props);
4097 return ERROR_SUCCESS;
4100 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4102 return execute_script(package,INSTALL_SCRIPT);
4105 static UINT msi_unpublish_product(MSIPACKAGE *package)
4107 LPWSTR remove = NULL;
4108 LPWSTR *features = NULL;
4109 BOOL full_uninstall = TRUE;
4110 MSIFEATURE *feature;
4112 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4113 static const WCHAR szAll[] = {'A','L','L',0};
4115 remove = msi_dup_property(package, szRemove);
4116 if (!remove)
4117 return ERROR_SUCCESS;
4119 features = msi_split_string(remove, ',');
4120 if (!features)
4122 msi_free(remove);
4123 ERR("REMOVE feature list is empty!\n");
4124 return ERROR_FUNCTION_FAILED;
4127 if (!lstrcmpW(features[0], szAll))
4128 full_uninstall = TRUE;
4129 else
4131 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4133 if (feature->Action != INSTALLSTATE_ABSENT)
4134 full_uninstall = FALSE;
4138 if (!full_uninstall)
4139 goto done;
4141 MSIREG_DeleteProductKey(package->ProductCode);
4142 MSIREG_DeleteUserProductKey(package->ProductCode);
4143 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4144 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4145 MSIREG_DeleteUninstallKey(package->ProductCode);
4147 done:
4148 msi_free(remove);
4149 msi_free(features);
4150 return ERROR_SUCCESS;
4153 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4155 UINT rc;
4157 rc = msi_unpublish_product(package);
4158 if (rc != ERROR_SUCCESS)
4159 return rc;
4161 /* turn off scheduling */
4162 package->script->CurrentlyScripting= FALSE;
4164 /* first do the same as an InstallExecute */
4165 rc = ACTION_InstallExecute(package);
4166 if (rc != ERROR_SUCCESS)
4167 return rc;
4169 /* then handle Commit Actions */
4170 rc = execute_script(package,COMMIT_SCRIPT);
4172 return rc;
4175 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4177 static const WCHAR RunOnce[] = {
4178 'S','o','f','t','w','a','r','e','\\',
4179 'M','i','c','r','o','s','o','f','t','\\',
4180 'W','i','n','d','o','w','s','\\',
4181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4182 'R','u','n','O','n','c','e',0};
4183 static const WCHAR InstallRunOnce[] = {
4184 'S','o','f','t','w','a','r','e','\\',
4185 'M','i','c','r','o','s','o','f','t','\\',
4186 'W','i','n','d','o','w','s','\\',
4187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4188 'I','n','s','t','a','l','l','e','r','\\',
4189 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4191 static const WCHAR msiexec_fmt[] = {
4192 '%','s',
4193 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4194 '\"','%','s','\"',0};
4195 static const WCHAR install_fmt[] = {
4196 '/','I',' ','\"','%','s','\"',' ',
4197 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4198 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4199 WCHAR buffer[256], sysdir[MAX_PATH];
4200 HKEY hkey;
4201 WCHAR squished_pc[100];
4203 squash_guid(package->ProductCode,squished_pc);
4205 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4206 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4207 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4208 squished_pc);
4210 msi_reg_set_val_str( hkey, squished_pc, buffer );
4211 RegCloseKey(hkey);
4213 TRACE("Reboot command %s\n",debugstr_w(buffer));
4215 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4216 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4218 msi_reg_set_val_str( hkey, squished_pc, buffer );
4219 RegCloseKey(hkey);
4221 return ERROR_INSTALL_SUSPEND;
4224 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4226 DWORD attrib;
4227 UINT rc;
4230 * We are currently doing what should be done here in the top level Install
4231 * however for Administrative and uninstalls this step will be needed
4233 if (!package->PackagePath)
4234 return ERROR_SUCCESS;
4236 msi_set_sourcedir_props(package, TRUE);
4238 attrib = GetFileAttributesW(package->db->path);
4239 if (attrib == INVALID_FILE_ATTRIBUTES)
4241 LPWSTR prompt;
4242 LPWSTR msg;
4243 DWORD size = 0;
4245 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4246 package->Context, MSICODE_PRODUCT,
4247 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4248 if (rc == ERROR_MORE_DATA)
4250 prompt = msi_alloc(size * sizeof(WCHAR));
4251 MsiSourceListGetInfoW(package->ProductCode, NULL,
4252 package->Context, MSICODE_PRODUCT,
4253 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4255 else
4256 prompt = strdupW(package->db->path);
4258 msg = generate_error_string(package,1302,1,prompt);
4259 while(attrib == INVALID_FILE_ATTRIBUTES)
4261 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4262 if (rc == IDCANCEL)
4264 rc = ERROR_INSTALL_USEREXIT;
4265 break;
4267 attrib = GetFileAttributesW(package->db->path);
4269 msi_free(prompt);
4270 rc = ERROR_SUCCESS;
4272 else
4273 return ERROR_SUCCESS;
4275 return rc;
4278 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4280 HKEY hkey=0;
4281 LPWSTR buffer;
4282 LPWSTR productid;
4283 UINT rc,i;
4285 static const WCHAR szPropKeys[][80] =
4287 {'P','r','o','d','u','c','t','I','D',0},
4288 {'U','S','E','R','N','A','M','E',0},
4289 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4290 {0},
4293 static const WCHAR szRegKeys[][80] =
4295 {'P','r','o','d','u','c','t','I','D',0},
4296 {'R','e','g','O','w','n','e','r',0},
4297 {'R','e','g','C','o','m','p','a','n','y',0},
4298 {0},
4301 if (msi_check_unpublish(package))
4303 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4304 return ERROR_SUCCESS;
4307 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4308 if (!productid)
4309 return ERROR_SUCCESS;
4311 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &hkey, TRUE);
4312 if (rc != ERROR_SUCCESS)
4313 goto end;
4315 for( i = 0; szPropKeys[i][0]; i++ )
4317 buffer = msi_dup_property( package, szPropKeys[i] );
4318 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4319 msi_free( buffer );
4322 end:
4323 msi_free(productid);
4324 RegCloseKey(hkey);
4326 /* FIXME: call ui_actiondata */
4328 return rc;
4332 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4334 UINT rc;
4336 package->script->InWhatSequence |= SEQUENCE_EXEC;
4337 rc = ACTION_ProcessExecSequence(package,FALSE);
4338 return rc;
4342 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4344 MSIPACKAGE *package = (MSIPACKAGE*)param;
4345 LPCWSTR compgroupid=NULL;
4346 LPCWSTR feature=NULL;
4347 LPCWSTR text = NULL;
4348 LPCWSTR qualifier = NULL;
4349 LPCWSTR component = NULL;
4350 LPWSTR advertise = NULL;
4351 LPWSTR output = NULL;
4352 HKEY hkey;
4353 UINT rc = ERROR_SUCCESS;
4354 MSICOMPONENT *comp;
4355 DWORD sz = 0;
4356 MSIRECORD *uirow;
4358 component = MSI_RecordGetString(rec,3);
4359 comp = get_loaded_component(package,component);
4361 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4362 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4363 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4365 TRACE("Skipping: Component %s not scheduled for install\n",
4366 debugstr_w(component));
4368 return ERROR_SUCCESS;
4371 compgroupid = MSI_RecordGetString(rec,1);
4372 qualifier = MSI_RecordGetString(rec,2);
4374 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4375 if (rc != ERROR_SUCCESS)
4376 goto end;
4378 text = MSI_RecordGetString(rec,4);
4379 feature = MSI_RecordGetString(rec,5);
4381 advertise = create_component_advertise_string(package, comp, feature);
4383 sz = strlenW(advertise);
4385 if (text)
4386 sz += lstrlenW(text);
4388 sz+=3;
4389 sz *= sizeof(WCHAR);
4391 output = msi_alloc_zero(sz);
4392 strcpyW(output,advertise);
4393 msi_free(advertise);
4395 if (text)
4396 strcatW(output,text);
4398 msi_reg_set_val_multi_str( hkey, qualifier, output );
4400 end:
4401 RegCloseKey(hkey);
4402 msi_free(output);
4404 /* the UI chunk */
4405 uirow = MSI_CreateRecord( 2 );
4406 MSI_RecordSetStringW( uirow, 1, compgroupid );
4407 MSI_RecordSetStringW( uirow, 2, qualifier);
4408 ui_actiondata( package, szPublishComponents, uirow);
4409 msiobj_release( &uirow->hdr );
4410 /* FIXME: call ui_progress? */
4412 return rc;
4416 * At present I am ignorning the advertised components part of this and only
4417 * focusing on the qualified component sets
4419 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4421 UINT rc;
4422 MSIQUERY * view;
4423 static const WCHAR ExecSeqQuery[] =
4424 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4425 '`','P','u','b','l','i','s','h',
4426 'C','o','m','p','o','n','e','n','t','`',0};
4428 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4429 if (rc != ERROR_SUCCESS)
4430 return ERROR_SUCCESS;
4432 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4433 msiobj_release(&view->hdr);
4435 return rc;
4438 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4440 MSIPACKAGE *package = (MSIPACKAGE*)param;
4441 MSIRECORD *row;
4442 MSIFILE *file;
4443 SC_HANDLE hscm, service = NULL;
4444 LPCWSTR comp, depends, pass;
4445 LPWSTR name = NULL, disp = NULL;
4446 LPCWSTR load_order, serv_name, key;
4447 DWORD serv_type, start_type;
4448 DWORD err_control;
4450 static const WCHAR query[] =
4451 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4452 '`','C','o','m','p','o','n','e','n','t','`',' ',
4453 'W','H','E','R','E',' ',
4454 '`','C','o','m','p','o','n','e','n','t','`',' ',
4455 '=','\'','%','s','\'',0};
4457 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4458 if (!hscm)
4460 ERR("Failed to open the SC Manager!\n");
4461 goto done;
4464 start_type = MSI_RecordGetInteger(rec, 5);
4465 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4466 goto done;
4468 depends = MSI_RecordGetString(rec, 8);
4469 if (depends && *depends)
4470 FIXME("Dependency list unhandled!\n");
4472 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4473 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4474 serv_type = MSI_RecordGetInteger(rec, 4);
4475 err_control = MSI_RecordGetInteger(rec, 6);
4476 load_order = MSI_RecordGetString(rec, 7);
4477 serv_name = MSI_RecordGetString(rec, 9);
4478 pass = MSI_RecordGetString(rec, 10);
4479 comp = MSI_RecordGetString(rec, 12);
4481 /* fetch the service path */
4482 row = MSI_QueryGetRecord(package->db, query, comp);
4483 if (!row)
4485 ERR("Control query failed!\n");
4486 goto done;
4489 key = MSI_RecordGetString(row, 6);
4491 file = get_loaded_file(package, key);
4492 msiobj_release(&row->hdr);
4493 if (!file)
4495 ERR("Failed to load the service file\n");
4496 goto done;
4499 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4500 start_type, err_control, file->TargetPath,
4501 load_order, NULL, NULL, serv_name, pass);
4502 if (!service)
4504 if (GetLastError() != ERROR_SERVICE_EXISTS)
4505 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4508 done:
4509 CloseServiceHandle(service);
4510 CloseServiceHandle(hscm);
4511 msi_free(name);
4512 msi_free(disp);
4514 return ERROR_SUCCESS;
4517 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4519 UINT rc;
4520 MSIQUERY * view;
4521 static const WCHAR ExecSeqQuery[] =
4522 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4523 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4525 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4526 if (rc != ERROR_SUCCESS)
4527 return ERROR_SUCCESS;
4529 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4530 msiobj_release(&view->hdr);
4532 return rc;
4535 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4536 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4538 LPCWSTR *vector, *temp_vector;
4539 LPWSTR p, q;
4540 DWORD sep_len;
4542 static const WCHAR separator[] = {'[','~',']',0};
4544 *numargs = 0;
4545 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4547 if (!args)
4548 return NULL;
4550 vector = msi_alloc(sizeof(LPWSTR));
4551 if (!vector)
4552 return NULL;
4554 p = args;
4557 (*numargs)++;
4558 vector[*numargs - 1] = p;
4560 if ((q = strstrW(p, separator)))
4562 *q = '\0';
4564 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4565 if (!temp_vector)
4567 msi_free(vector);
4568 return NULL;
4570 vector = temp_vector;
4572 p = q + sep_len;
4574 } while (q);
4576 return vector;
4579 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4581 MSIPACKAGE *package = (MSIPACKAGE *)param;
4582 MSICOMPONENT *comp;
4583 SC_HANDLE scm, service = NULL;
4584 LPCWSTR name, *vector = NULL;
4585 LPWSTR args;
4586 DWORD event, numargs;
4587 UINT r = ERROR_FUNCTION_FAILED;
4589 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4590 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4591 return ERROR_SUCCESS;
4593 name = MSI_RecordGetString(rec, 2);
4594 event = MSI_RecordGetInteger(rec, 3);
4595 args = strdupW(MSI_RecordGetString(rec, 4));
4597 if (!(event & msidbServiceControlEventStart))
4598 return ERROR_SUCCESS;
4600 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4601 if (!scm)
4603 ERR("Failed to open the service control manager\n");
4604 goto done;
4607 service = OpenServiceW(scm, name, SERVICE_START);
4608 if (!service)
4610 ERR("Failed to open service %s\n", debugstr_w(name));
4611 goto done;
4614 vector = msi_service_args_to_vector(args, &numargs);
4616 if (!StartServiceW(service, numargs, vector))
4618 ERR("Failed to start service %s\n", debugstr_w(name));
4619 goto done;
4622 r = ERROR_SUCCESS;
4624 done:
4625 CloseServiceHandle(service);
4626 CloseServiceHandle(scm);
4628 msi_free(args);
4629 msi_free(vector);
4630 return r;
4633 static UINT ACTION_StartServices( MSIPACKAGE *package )
4635 UINT rc;
4636 MSIQUERY *view;
4638 static const WCHAR query[] = {
4639 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4640 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4642 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4643 if (rc != ERROR_SUCCESS)
4644 return ERROR_SUCCESS;
4646 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4647 msiobj_release(&view->hdr);
4649 return rc;
4652 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4654 DWORD i, needed, count;
4655 ENUM_SERVICE_STATUSW *dependencies;
4656 SERVICE_STATUS ss;
4657 SC_HANDLE depserv;
4659 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4660 0, &needed, &count))
4661 return TRUE;
4663 if (GetLastError() != ERROR_MORE_DATA)
4664 return FALSE;
4666 dependencies = msi_alloc(needed);
4667 if (!dependencies)
4668 return FALSE;
4670 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4671 needed, &needed, &count))
4672 goto error;
4674 for (i = 0; i < count; i++)
4676 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4677 SERVICE_STOP | SERVICE_QUERY_STATUS);
4678 if (!depserv)
4679 goto error;
4681 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4682 goto error;
4685 return TRUE;
4687 error:
4688 msi_free(dependencies);
4689 return FALSE;
4692 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4694 MSIPACKAGE *package = (MSIPACKAGE *)param;
4695 MSICOMPONENT *comp;
4696 SERVICE_STATUS status;
4697 SERVICE_STATUS_PROCESS ssp;
4698 SC_HANDLE scm = NULL, service = NULL;
4699 LPWSTR name, args;
4700 DWORD event, needed;
4702 event = MSI_RecordGetInteger(rec, 3);
4703 if (!(event & msidbServiceControlEventStop))
4704 return ERROR_SUCCESS;
4706 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4707 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4708 return ERROR_SUCCESS;
4710 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4711 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4712 args = strdupW(MSI_RecordGetString(rec, 4));
4714 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4715 if (!scm)
4717 WARN("Failed to open the SCM: %d\n", GetLastError());
4718 goto done;
4721 service = OpenServiceW(scm, name,
4722 SERVICE_STOP |
4723 SERVICE_QUERY_STATUS |
4724 SERVICE_ENUMERATE_DEPENDENTS);
4725 if (!service)
4727 WARN("Failed to open service (%s): %d\n",
4728 debugstr_w(name), GetLastError());
4729 goto done;
4732 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4733 sizeof(SERVICE_STATUS_PROCESS), &needed))
4735 WARN("Failed to query service status (%s): %d\n",
4736 debugstr_w(name), GetLastError());
4737 goto done;
4740 if (ssp.dwCurrentState == SERVICE_STOPPED)
4741 goto done;
4743 stop_service_dependents(scm, service);
4745 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4746 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4748 done:
4749 CloseServiceHandle(service);
4750 CloseServiceHandle(scm);
4751 msi_free(name);
4752 msi_free(args);
4754 return ERROR_SUCCESS;
4757 static UINT ACTION_StopServices( MSIPACKAGE *package )
4759 UINT rc;
4760 MSIQUERY *view;
4762 static const WCHAR query[] = {
4763 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4764 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4766 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4767 if (rc != ERROR_SUCCESS)
4768 return ERROR_SUCCESS;
4770 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4771 msiobj_release(&view->hdr);
4773 return rc;
4776 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4778 MSIFILE *file;
4780 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4782 if (!lstrcmpW(file->File, filename))
4783 return file;
4786 return NULL;
4789 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4791 MSIPACKAGE *package = (MSIPACKAGE*)param;
4792 LPWSTR driver, driver_path, ptr;
4793 WCHAR outpath[MAX_PATH];
4794 MSIFILE *driver_file, *setup_file;
4795 LPCWSTR desc;
4796 DWORD len, usage;
4797 UINT r = ERROR_SUCCESS;
4799 static const WCHAR driver_fmt[] = {
4800 'D','r','i','v','e','r','=','%','s',0};
4801 static const WCHAR setup_fmt[] = {
4802 'S','e','t','u','p','=','%','s',0};
4803 static const WCHAR usage_fmt[] = {
4804 'F','i','l','e','U','s','a','g','e','=','1',0};
4806 desc = MSI_RecordGetString(rec, 3);
4808 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4809 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4811 if (!driver_file || !setup_file)
4813 ERR("ODBC Driver entry not found!\n");
4814 return ERROR_FUNCTION_FAILED;
4817 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4818 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4819 lstrlenW(usage_fmt) + 1;
4820 driver = msi_alloc(len * sizeof(WCHAR));
4821 if (!driver)
4822 return ERROR_OUTOFMEMORY;
4824 ptr = driver;
4825 lstrcpyW(ptr, desc);
4826 ptr += lstrlenW(ptr) + 1;
4828 sprintfW(ptr, driver_fmt, driver_file->FileName);
4829 ptr += lstrlenW(ptr) + 1;
4831 sprintfW(ptr, setup_fmt, setup_file->FileName);
4832 ptr += lstrlenW(ptr) + 1;
4834 lstrcpyW(ptr, usage_fmt);
4835 ptr += lstrlenW(ptr) + 1;
4836 *ptr = '\0';
4838 driver_path = strdupW(driver_file->TargetPath);
4839 ptr = strrchrW(driver_path, '\\');
4840 if (ptr) *ptr = '\0';
4842 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4843 NULL, ODBC_INSTALL_COMPLETE, &usage))
4845 ERR("Failed to install SQL driver!\n");
4846 r = ERROR_FUNCTION_FAILED;
4849 msi_free(driver);
4850 msi_free(driver_path);
4852 return r;
4855 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4857 MSIPACKAGE *package = (MSIPACKAGE*)param;
4858 LPWSTR translator, translator_path, ptr;
4859 WCHAR outpath[MAX_PATH];
4860 MSIFILE *translator_file, *setup_file;
4861 LPCWSTR desc;
4862 DWORD len, usage;
4863 UINT r = ERROR_SUCCESS;
4865 static const WCHAR translator_fmt[] = {
4866 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4867 static const WCHAR setup_fmt[] = {
4868 'S','e','t','u','p','=','%','s',0};
4870 desc = MSI_RecordGetString(rec, 3);
4872 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4873 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4875 if (!translator_file || !setup_file)
4877 ERR("ODBC Translator entry not found!\n");
4878 return ERROR_FUNCTION_FAILED;
4881 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4882 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4883 translator = msi_alloc(len * sizeof(WCHAR));
4884 if (!translator)
4885 return ERROR_OUTOFMEMORY;
4887 ptr = translator;
4888 lstrcpyW(ptr, desc);
4889 ptr += lstrlenW(ptr) + 1;
4891 sprintfW(ptr, translator_fmt, translator_file->FileName);
4892 ptr += lstrlenW(ptr) + 1;
4894 sprintfW(ptr, setup_fmt, setup_file->FileName);
4895 ptr += lstrlenW(ptr) + 1;
4896 *ptr = '\0';
4898 translator_path = strdupW(translator_file->TargetPath);
4899 ptr = strrchrW(translator_path, '\\');
4900 if (ptr) *ptr = '\0';
4902 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4903 NULL, ODBC_INSTALL_COMPLETE, &usage))
4905 ERR("Failed to install SQL translator!\n");
4906 r = ERROR_FUNCTION_FAILED;
4909 msi_free(translator);
4910 msi_free(translator_path);
4912 return r;
4915 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4917 LPWSTR attrs;
4918 LPCWSTR desc, driver;
4919 WORD request = ODBC_ADD_SYS_DSN;
4920 INT registration;
4921 DWORD len;
4922 UINT r = ERROR_SUCCESS;
4924 static const WCHAR attrs_fmt[] = {
4925 'D','S','N','=','%','s',0 };
4927 desc = MSI_RecordGetString(rec, 3);
4928 driver = MSI_RecordGetString(rec, 4);
4929 registration = MSI_RecordGetInteger(rec, 5);
4931 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4932 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4934 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4935 attrs = msi_alloc(len * sizeof(WCHAR));
4936 if (!attrs)
4937 return ERROR_OUTOFMEMORY;
4939 sprintfW(attrs, attrs_fmt, desc);
4940 attrs[len - 1] = '\0';
4942 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4944 ERR("Failed to install SQL data source!\n");
4945 r = ERROR_FUNCTION_FAILED;
4948 msi_free(attrs);
4950 return r;
4953 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4955 UINT rc;
4956 MSIQUERY *view;
4958 static const WCHAR driver_query[] = {
4959 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4960 'O','D','B','C','D','r','i','v','e','r',0 };
4962 static const WCHAR translator_query[] = {
4963 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4964 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4966 static const WCHAR source_query[] = {
4967 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4968 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4970 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4971 if (rc != ERROR_SUCCESS)
4972 return ERROR_SUCCESS;
4974 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4975 msiobj_release(&view->hdr);
4977 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4978 if (rc != ERROR_SUCCESS)
4979 return ERROR_SUCCESS;
4981 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4982 msiobj_release(&view->hdr);
4984 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4985 if (rc != ERROR_SUCCESS)
4986 return ERROR_SUCCESS;
4988 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4989 msiobj_release(&view->hdr);
4991 return rc;
4994 #define ENV_ACT_SETALWAYS 0x1
4995 #define ENV_ACT_SETABSENT 0x2
4996 #define ENV_ACT_REMOVE 0x4
4997 #define ENV_ACT_REMOVEMATCH 0x8
4999 #define ENV_MOD_MACHINE 0x20000000
5000 #define ENV_MOD_APPEND 0x40000000
5001 #define ENV_MOD_PREFIX 0x80000000
5002 #define ENV_MOD_MASK 0xC0000000
5004 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5006 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5008 LPCWSTR cptr = *name;
5009 LPCWSTR ptr = *value;
5011 static const WCHAR prefix[] = {'[','~',']',0};
5012 static const int prefix_len = 3;
5014 *flags = 0;
5015 while (*cptr)
5017 if (*cptr == '=')
5018 *flags |= ENV_ACT_SETALWAYS;
5019 else if (*cptr == '+')
5020 *flags |= ENV_ACT_SETABSENT;
5021 else if (*cptr == '-')
5022 *flags |= ENV_ACT_REMOVE;
5023 else if (*cptr == '!')
5024 *flags |= ENV_ACT_REMOVEMATCH;
5025 else if (*cptr == '*')
5026 *flags |= ENV_MOD_MACHINE;
5027 else
5028 break;
5030 cptr++;
5031 (*name)++;
5034 if (!*cptr)
5036 ERR("Missing environment variable\n");
5037 return ERROR_FUNCTION_FAILED;
5040 if (!strncmpW(ptr, prefix, prefix_len))
5042 *flags |= ENV_MOD_APPEND;
5043 *value += lstrlenW(prefix);
5045 else if (lstrlenW(*value) >= prefix_len)
5047 ptr += lstrlenW(ptr) - prefix_len;
5048 if (!lstrcmpW(ptr, prefix))
5050 *flags |= ENV_MOD_PREFIX;
5051 /* the "[~]" will be removed by deformat_string */;
5055 if (!*flags ||
5056 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5057 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5058 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5059 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5061 ERR("Invalid flags: %08x\n", *flags);
5062 return ERROR_FUNCTION_FAILED;
5065 return ERROR_SUCCESS;
5068 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5070 MSIPACKAGE *package = param;
5071 LPCWSTR name, value, comp;
5072 LPWSTR data = NULL, newval = NULL;
5073 LPWSTR deformatted = NULL, ptr;
5074 DWORD flags, type, size;
5075 LONG res;
5076 HKEY env = NULL, root;
5077 LPCWSTR environment;
5079 static const WCHAR user_env[] =
5080 {'E','n','v','i','r','o','n','m','e','n','t',0};
5081 static const WCHAR machine_env[] =
5082 {'S','y','s','t','e','m','\\',
5083 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5084 'C','o','n','t','r','o','l','\\',
5085 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5086 'E','n','v','i','r','o','n','m','e','n','t',0};
5087 static const WCHAR semicolon[] = {';',0};
5089 name = MSI_RecordGetString(rec, 2);
5090 value = MSI_RecordGetString(rec, 3);
5091 comp = MSI_RecordGetString(rec, 4);
5093 res = env_set_flags(&name, &value, &flags);
5094 if (res != ERROR_SUCCESS)
5095 goto done;
5097 deformat_string(package, value, &deformatted);
5098 if (!deformatted)
5100 res = ERROR_OUTOFMEMORY;
5101 goto done;
5104 value = deformatted;
5106 if (flags & ENV_MOD_MACHINE)
5108 environment = machine_env;
5109 root = HKEY_LOCAL_MACHINE;
5111 else
5113 environment = user_env;
5114 root = HKEY_CURRENT_USER;
5117 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5118 KEY_ALL_ACCESS, NULL, &env, NULL);
5119 if (res != ERROR_SUCCESS)
5120 goto done;
5122 if (flags & ENV_ACT_REMOVE)
5123 FIXME("Not removing environment variable on uninstall!\n");
5125 size = 0;
5126 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5127 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5128 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5129 goto done;
5131 if (res != ERROR_FILE_NOT_FOUND)
5133 if (flags & ENV_ACT_SETABSENT)
5135 res = ERROR_SUCCESS;
5136 goto done;
5139 data = msi_alloc(size);
5140 if (!data)
5142 RegCloseKey(env);
5143 return ERROR_OUTOFMEMORY;
5146 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5147 if (res != ERROR_SUCCESS)
5148 goto done;
5150 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5152 res = RegDeleteKeyW(env, name);
5153 goto done;
5156 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5157 newval = msi_alloc(size);
5158 ptr = newval;
5159 if (!newval)
5161 res = ERROR_OUTOFMEMORY;
5162 goto done;
5165 if (!(flags & ENV_MOD_MASK))
5166 lstrcpyW(newval, value);
5167 else
5169 if (flags & ENV_MOD_PREFIX)
5171 lstrcpyW(newval, value);
5172 lstrcatW(newval, semicolon);
5173 ptr = newval + lstrlenW(value) + 1;
5176 lstrcpyW(ptr, data);
5178 if (flags & ENV_MOD_APPEND)
5180 lstrcatW(newval, semicolon);
5181 lstrcatW(newval, value);
5185 else
5187 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5188 newval = msi_alloc(size);
5189 if (!newval)
5191 res = ERROR_OUTOFMEMORY;
5192 goto done;
5195 lstrcpyW(newval, value);
5198 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5199 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5201 done:
5202 if (env) RegCloseKey(env);
5203 msi_free(deformatted);
5204 msi_free(data);
5205 msi_free(newval);
5206 return res;
5209 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5211 UINT rc;
5212 MSIQUERY * view;
5213 static const WCHAR ExecSeqQuery[] =
5214 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5215 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5216 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5217 if (rc != ERROR_SUCCESS)
5218 return ERROR_SUCCESS;
5220 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5221 msiobj_release(&view->hdr);
5223 return rc;
5226 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5228 typedef struct
5230 struct list entry;
5231 LPWSTR sourcename;
5232 LPWSTR destname;
5233 LPWSTR source;
5234 LPWSTR dest;
5235 } FILE_LIST;
5237 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5239 BOOL ret;
5241 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5242 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5244 WARN("Source or dest is directory, not moving\n");
5245 return FALSE;
5248 if (options == msidbMoveFileOptionsMove)
5250 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5251 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5252 if (!ret)
5254 WARN("MoveFile failed: %d\n", GetLastError());
5255 return FALSE;
5258 else
5260 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5261 ret = CopyFileW(source, dest, FALSE);
5262 if (!ret)
5264 WARN("CopyFile failed: %d\n", GetLastError());
5265 return FALSE;
5269 return TRUE;
5272 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5274 LPWSTR path, ptr;
5275 DWORD dirlen, pathlen;
5277 ptr = strrchrW(wildcard, '\\');
5278 dirlen = ptr - wildcard + 1;
5280 pathlen = dirlen + lstrlenW(filename) + 1;
5281 path = msi_alloc(pathlen * sizeof(WCHAR));
5283 lstrcpynW(path, wildcard, dirlen + 1);
5284 lstrcatW(path, filename);
5286 return path;
5289 static void free_file_entry(FILE_LIST *file)
5291 msi_free(file->source);
5292 msi_free(file->dest);
5293 msi_free(file);
5296 static void free_list(FILE_LIST *list)
5298 while (!list_empty(&list->entry))
5300 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5302 list_remove(&file->entry);
5303 free_file_entry(file);
5307 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5309 FILE_LIST *new, *file;
5310 LPWSTR ptr, filename;
5311 DWORD size;
5313 new = msi_alloc_zero(sizeof(FILE_LIST));
5314 if (!new)
5315 return FALSE;
5317 new->source = strdupW(source);
5318 ptr = strrchrW(dest, '\\') + 1;
5319 filename = strrchrW(new->source, '\\') + 1;
5321 new->sourcename = filename;
5323 if (*ptr)
5324 new->destname = ptr;
5325 else
5326 new->destname = new->sourcename;
5328 size = (ptr - dest) + lstrlenW(filename) + 1;
5329 new->dest = msi_alloc(size * sizeof(WCHAR));
5330 if (!new->dest)
5332 free_file_entry(new);
5333 return FALSE;
5336 lstrcpynW(new->dest, dest, ptr - dest + 1);
5337 lstrcatW(new->dest, filename);
5339 if (list_empty(&files->entry))
5341 list_add_head(&files->entry, &new->entry);
5342 return TRUE;
5345 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5347 if (lstrcmpW(source, file->source) < 0)
5349 list_add_before(&file->entry, &new->entry);
5350 return TRUE;
5354 list_add_after(&file->entry, &new->entry);
5355 return TRUE;
5358 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5360 WIN32_FIND_DATAW wfd;
5361 HANDLE hfile;
5362 LPWSTR path;
5363 BOOL res;
5364 FILE_LIST files, *file;
5365 DWORD size;
5367 hfile = FindFirstFileW(source, &wfd);
5368 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5370 list_init(&files.entry);
5372 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5374 if (is_dot_dir(wfd.cFileName)) continue;
5376 path = wildcard_to_file(source, wfd.cFileName);
5377 if (!path)
5379 res = FALSE;
5380 goto done;
5383 add_wildcard(&files, path, dest);
5384 msi_free(path);
5387 /* no files match the wildcard */
5388 if (list_empty(&files.entry))
5389 goto done;
5391 /* only the first wildcard match gets renamed to dest */
5392 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5393 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5394 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5395 if (!file->dest)
5397 res = FALSE;
5398 goto done;
5401 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5403 while (!list_empty(&files.entry))
5405 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5407 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5409 list_remove(&file->entry);
5410 free_file_entry(file);
5413 res = TRUE;
5415 done:
5416 free_list(&files);
5417 FindClose(hfile);
5418 return res;
5421 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5423 MSIPACKAGE *package = param;
5424 MSICOMPONENT *comp;
5425 LPCWSTR sourcename, destname;
5426 LPWSTR sourcedir = NULL, destdir = NULL;
5427 LPWSTR source = NULL, dest = NULL;
5428 int options;
5429 DWORD size;
5430 BOOL ret, wildcards;
5432 static const WCHAR backslash[] = {'\\',0};
5434 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5435 if (!comp || !comp->Enabled ||
5436 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5438 TRACE("Component not set for install, not moving file\n");
5439 return ERROR_SUCCESS;
5442 sourcename = MSI_RecordGetString(rec, 3);
5443 destname = MSI_RecordGetString(rec, 4);
5444 options = MSI_RecordGetInteger(rec, 7);
5446 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5447 if (!sourcedir)
5448 goto done;
5450 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5451 if (!destdir)
5452 goto done;
5454 if (!sourcename)
5456 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5457 goto done;
5459 source = strdupW(sourcedir);
5460 if (!source)
5461 goto done;
5463 else
5465 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5466 source = msi_alloc(size * sizeof(WCHAR));
5467 if (!source)
5468 goto done;
5470 lstrcpyW(source, sourcedir);
5471 if (source[lstrlenW(source) - 1] != '\\')
5472 lstrcatW(source, backslash);
5473 lstrcatW(source, sourcename);
5476 wildcards = strchrW(source, '*') || strchrW(source, '?');
5478 if (!destname && !wildcards)
5480 destname = strdupW(sourcename);
5481 if (!destname)
5482 goto done;
5485 size = 0;
5486 if (destname)
5487 size = lstrlenW(destname);
5489 size += lstrlenW(destdir) + 2;
5490 dest = msi_alloc(size * sizeof(WCHAR));
5491 if (!dest)
5492 goto done;
5494 lstrcpyW(dest, destdir);
5495 if (dest[lstrlenW(dest) - 1] != '\\')
5496 lstrcatW(dest, backslash);
5498 if (destname)
5499 lstrcatW(dest, destname);
5501 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5503 ret = CreateDirectoryW(destdir, NULL);
5504 if (!ret)
5506 WARN("CreateDirectory failed: %d\n", GetLastError());
5507 return ERROR_SUCCESS;
5511 if (!wildcards)
5512 msi_move_file(source, dest, options);
5513 else
5514 move_files_wildcard(source, dest, options);
5516 done:
5517 msi_free(sourcedir);
5518 msi_free(destdir);
5519 msi_free(source);
5520 msi_free(dest);
5522 return ERROR_SUCCESS;
5525 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5527 UINT rc;
5528 MSIQUERY *view;
5530 static const WCHAR ExecSeqQuery[] =
5531 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5532 '`','M','o','v','e','F','i','l','e','`',0};
5534 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5535 if (rc != ERROR_SUCCESS)
5536 return ERROR_SUCCESS;
5538 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5539 msiobj_release(&view->hdr);
5541 return rc;
5544 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5545 LPCSTR action, LPCWSTR table )
5547 static const WCHAR query[] = {
5548 'S','E','L','E','C','T',' ','*',' ',
5549 'F','R','O','M',' ','`','%','s','`',0 };
5550 MSIQUERY *view = NULL;
5551 DWORD count = 0;
5552 UINT r;
5554 r = MSI_OpenQuery( package->db, &view, query, table );
5555 if (r == ERROR_SUCCESS)
5557 r = MSI_IterateRecords(view, &count, NULL, package);
5558 msiobj_release(&view->hdr);
5561 if (count)
5562 FIXME("%s -> %u ignored %s table values\n",
5563 action, count, debugstr_w(table));
5565 return ERROR_SUCCESS;
5568 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5570 TRACE("%p\n", package);
5571 return ERROR_SUCCESS;
5574 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5576 static const WCHAR table[] =
5577 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5578 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5581 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5583 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5584 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5587 static UINT ACTION_BindImage( MSIPACKAGE *package )
5589 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5590 return msi_unimplemented_action_stub( package, "BindImage", table );
5593 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5595 static const WCHAR table[] = {
5596 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5597 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5600 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5602 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5603 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5606 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5608 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5609 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5612 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5614 static const WCHAR table[] = {
5615 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5616 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5618 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5620 static const WCHAR table[] = {
5621 'P','r','o','d','u','c','t','I','D',0 };
5622 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5625 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5627 static const WCHAR table[] = {
5628 'E','n','v','i','r','o','n','m','e','n','t',0 };
5629 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5632 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5634 static const WCHAR table[] = {
5635 'M','s','i','A','s','s','e','m','b','l','y',0 };
5636 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
5639 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5641 static const WCHAR table[] = {
5642 'M','s','i','A','s','s','e','m','b','l','y',0 };
5643 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5646 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5648 static const WCHAR table[] = { 'F','o','n','t',0 };
5649 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5652 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5654 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5655 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5658 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5660 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5661 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5664 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5666 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5667 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5670 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5672 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5673 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5676 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5678 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5679 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5682 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5684 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5685 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5688 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5690 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5691 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5694 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5696 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5697 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5700 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5702 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5703 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5706 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5708 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5709 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5712 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5714 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5715 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5718 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5720 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5721 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5724 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5726 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5727 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5730 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5732 static const WCHAR table[] = { 'M','I','M','E',0 };
5733 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5736 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5738 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5739 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5742 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5744 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5745 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5748 static const struct _actions StandardActions[] = {
5749 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5750 { szAppSearch, ACTION_AppSearch },
5751 { szBindImage, ACTION_BindImage },
5752 { szCCPSearch, ACTION_CCPSearch },
5753 { szCostFinalize, ACTION_CostFinalize },
5754 { szCostInitialize, ACTION_CostInitialize },
5755 { szCreateFolders, ACTION_CreateFolders },
5756 { szCreateShortcuts, ACTION_CreateShortcuts },
5757 { szDeleteServices, ACTION_DeleteServices },
5758 { szDisableRollback, NULL },
5759 { szDuplicateFiles, ACTION_DuplicateFiles },
5760 { szExecuteAction, ACTION_ExecuteAction },
5761 { szFileCost, ACTION_FileCost },
5762 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5763 { szForceReboot, ACTION_ForceReboot },
5764 { szInstallAdminPackage, NULL },
5765 { szInstallExecute, ACTION_InstallExecute },
5766 { szInstallExecuteAgain, ACTION_InstallExecute },
5767 { szInstallFiles, ACTION_InstallFiles},
5768 { szInstallFinalize, ACTION_InstallFinalize },
5769 { szInstallInitialize, ACTION_InstallInitialize },
5770 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5771 { szInstallValidate, ACTION_InstallValidate },
5772 { szIsolateComponents, ACTION_IsolateComponents },
5773 { szLaunchConditions, ACTION_LaunchConditions },
5774 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5775 { szMoveFiles, ACTION_MoveFiles },
5776 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5777 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5778 { szInstallODBC, ACTION_InstallODBC },
5779 { szInstallServices, ACTION_InstallServices },
5780 { szPatchFiles, ACTION_PatchFiles },
5781 { szProcessComponents, ACTION_ProcessComponents },
5782 { szPublishComponents, ACTION_PublishComponents },
5783 { szPublishFeatures, ACTION_PublishFeatures },
5784 { szPublishProduct, ACTION_PublishProduct },
5785 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5786 { szRegisterComPlus, ACTION_RegisterComPlus},
5787 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5788 { szRegisterFonts, ACTION_RegisterFonts },
5789 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5790 { szRegisterProduct, ACTION_RegisterProduct },
5791 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5792 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5793 { szRegisterUser, ACTION_RegisterUser },
5794 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5795 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5796 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5797 { szRemoveFiles, ACTION_RemoveFiles },
5798 { szRemoveFolders, ACTION_RemoveFolders },
5799 { szRemoveIniValues, ACTION_RemoveIniValues },
5800 { szRemoveODBC, ACTION_RemoveODBC },
5801 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5802 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5803 { szResolveSource, ACTION_ResolveSource },
5804 { szRMCCPSearch, ACTION_RMCCPSearch },
5805 { szScheduleReboot, NULL },
5806 { szSelfRegModules, ACTION_SelfRegModules },
5807 { szSelfUnregModules, ACTION_SelfUnregModules },
5808 { szSetODBCFolders, NULL },
5809 { szStartServices, ACTION_StartServices },
5810 { szStopServices, ACTION_StopServices },
5811 { szUnpublishComponents, ACTION_UnpublishComponents },
5812 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5813 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5814 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5815 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5816 { szUnregisterFonts, ACTION_UnregisterFonts },
5817 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5818 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5819 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5820 { szValidateProductID, ACTION_ValidateProductID },
5821 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5822 { szWriteIniValues, ACTION_WriteIniValues },
5823 { szWriteRegistryValues, ACTION_WriteRegistryValues },
5824 { NULL, NULL },
5827 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
5828 UINT* rc, BOOL force )
5830 BOOL ret = FALSE;
5831 BOOL run = force;
5832 int i;
5834 if (!run && !package->script->CurrentlyScripting)
5835 run = TRUE;
5837 if (!run)
5839 if (strcmpW(action,szInstallFinalize) == 0 ||
5840 strcmpW(action,szInstallExecute) == 0 ||
5841 strcmpW(action,szInstallExecuteAgain) == 0)
5842 run = TRUE;
5845 i = 0;
5846 while (StandardActions[i].action != NULL)
5848 if (strcmpW(StandardActions[i].action, action)==0)
5850 if (!run)
5852 ui_actioninfo(package, action, TRUE, 0);
5853 *rc = schedule_action(package,INSTALL_SCRIPT,action);
5854 ui_actioninfo(package, action, FALSE, *rc);
5856 else
5858 ui_actionstart(package, action);
5859 if (StandardActions[i].handler)
5861 *rc = StandardActions[i].handler(package);
5863 else
5865 FIXME("unhandled standard action %s\n",debugstr_w(action));
5866 *rc = ERROR_SUCCESS;
5869 ret = TRUE;
5870 break;
5872 i++;
5874 return ret;