mshtml: Added IDispatchEx support to HTMLImgElement.
[wine/multimedia.git] / dlls / msi / action.c
blob749da324cb48e60d3255558fe552f15075f42503
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 "objbase.h"
37 #include "mscoree.h"
38 #include "fusion.h"
39 #include "shlwapi.h"
40 #include "wine/unicode.h"
41 #include "winver.h"
43 #define REG_PROGRESS_VALUE 13200
44 #define COMPONENT_PROGRESS_VALUE 24000
46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
49 * Prototypes
51 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
52 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
53 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
54 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
57 * consts and values used
59 static const WCHAR c_colon[] = {'C',':','\\',0};
61 static const WCHAR szCreateFolders[] =
62 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
63 static const WCHAR szCostFinalize[] =
64 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
65 const WCHAR szInstallFiles[] =
66 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
67 const WCHAR szDuplicateFiles[] =
68 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
69 static const WCHAR szWriteRegistryValues[] =
70 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
71 'V','a','l','u','e','s',0};
72 static const WCHAR szCostInitialize[] =
73 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
74 static const WCHAR szFileCost[] =
75 {'F','i','l','e','C','o','s','t',0};
76 static const WCHAR szInstallInitialize[] =
77 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
78 static const WCHAR szInstallValidate[] =
79 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
80 static const WCHAR szLaunchConditions[] =
81 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
82 static const WCHAR szProcessComponents[] =
83 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
84 static const WCHAR szRegisterTypeLibraries[] =
85 {'R','e','g','i','s','t','e','r','T','y','p','e',
86 'L','i','b','r','a','r','i','e','s',0};
87 const WCHAR szRegisterClassInfo[] =
88 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
89 const WCHAR szRegisterProgIdInfo[] =
90 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
91 static const WCHAR szCreateShortcuts[] =
92 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
93 static const WCHAR szPublishProduct[] =
94 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
95 static const WCHAR szWriteIniValues[] =
96 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
97 static const WCHAR szSelfRegModules[] =
98 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
99 static const WCHAR szPublishFeatures[] =
100 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
101 static const WCHAR szRegisterProduct[] =
102 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
103 static const WCHAR szInstallExecute[] =
104 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
105 static const WCHAR szInstallExecuteAgain[] =
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
107 'A','g','a','i','n',0};
108 static const WCHAR szInstallFinalize[] =
109 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
110 static const WCHAR szForceReboot[] =
111 {'F','o','r','c','e','R','e','b','o','o','t',0};
112 static const WCHAR szResolveSource[] =
113 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
114 static const WCHAR szAppSearch[] =
115 {'A','p','p','S','e','a','r','c','h',0};
116 static const WCHAR szAllocateRegistrySpace[] =
117 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
118 'S','p','a','c','e',0};
119 static const WCHAR szBindImage[] =
120 {'B','i','n','d','I','m','a','g','e',0};
121 static const WCHAR szCCPSearch[] =
122 {'C','C','P','S','e','a','r','c','h',0};
123 static const WCHAR szDeleteServices[] =
124 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
125 static const WCHAR szDisableRollback[] =
126 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
127 static const WCHAR szExecuteAction[] =
128 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
129 const WCHAR szFindRelatedProducts[] =
130 {'F','i','n','d','R','e','l','a','t','e','d',
131 'P','r','o','d','u','c','t','s',0};
132 static const WCHAR szInstallAdminPackage[] =
133 {'I','n','s','t','a','l','l','A','d','m','i','n',
134 'P','a','c','k','a','g','e',0};
135 static const WCHAR szInstallSFPCatalogFile[] =
136 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
137 'F','i','l','e',0};
138 static const WCHAR szIsolateComponents[] =
139 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
140 const WCHAR szMigrateFeatureStates[] =
141 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
142 'S','t','a','t','e','s',0};
143 const WCHAR szMoveFiles[] =
144 {'M','o','v','e','F','i','l','e','s',0};
145 static const WCHAR szMsiPublishAssemblies[] =
146 {'M','s','i','P','u','b','l','i','s','h',
147 'A','s','s','e','m','b','l','i','e','s',0};
148 static const WCHAR szMsiUnpublishAssemblies[] =
149 {'M','s','i','U','n','p','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
151 static const WCHAR szInstallODBC[] =
152 {'I','n','s','t','a','l','l','O','D','B','C',0};
153 static const WCHAR szInstallServices[] =
154 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
155 const WCHAR szPatchFiles[] =
156 {'P','a','t','c','h','F','i','l','e','s',0};
157 static const WCHAR szPublishComponents[] =
158 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
159 static const WCHAR szRegisterComPlus[] =
160 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
161 const WCHAR szRegisterExtensionInfo[] =
162 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
163 'I','n','f','o',0};
164 static const WCHAR szRegisterFonts[] =
165 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
166 const WCHAR szRegisterMIMEInfo[] =
167 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
168 static const WCHAR szRegisterUser[] =
169 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
170 const WCHAR szRemoveDuplicateFiles[] =
171 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
172 'F','i','l','e','s',0};
173 static const WCHAR szRemoveEnvironmentStrings[] =
174 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
175 'S','t','r','i','n','g','s',0};
176 const WCHAR szRemoveExistingProducts[] =
177 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
178 'P','r','o','d','u','c','t','s',0};
179 const WCHAR szRemoveFiles[] =
180 {'R','e','m','o','v','e','F','i','l','e','s',0};
181 static const WCHAR szRemoveFolders[] =
182 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
183 static const WCHAR szRemoveIniValues[] =
184 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
185 static const WCHAR szRemoveODBC[] =
186 {'R','e','m','o','v','e','O','D','B','C',0};
187 static const WCHAR szRemoveRegistryValues[] =
188 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
189 'V','a','l','u','e','s',0};
190 static const WCHAR szRemoveShortcuts[] =
191 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
192 static const WCHAR szRMCCPSearch[] =
193 {'R','M','C','C','P','S','e','a','r','c','h',0};
194 static const WCHAR szScheduleReboot[] =
195 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
196 static const WCHAR szSelfUnregModules[] =
197 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
198 static const WCHAR szSetODBCFolders[] =
199 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
200 static const WCHAR szStartServices[] =
201 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
202 static const WCHAR szStopServices[] =
203 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szUnpublishComponents[] =
205 {'U','n','p','u','b','l','i','s','h',
206 'C','o','m','p','o','n','e','n','t','s',0};
207 static const WCHAR szUnpublishFeatures[] =
208 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
209 const WCHAR szUnregisterClassInfo[] =
210 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
211 'I','n','f','o',0};
212 static const WCHAR szUnregisterComPlus[] =
213 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
214 const WCHAR szUnregisterExtensionInfo[] =
215 {'U','n','r','e','g','i','s','t','e','r',
216 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
217 static const WCHAR szUnregisterFonts[] =
218 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
219 const WCHAR szUnregisterMIMEInfo[] =
220 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
221 const WCHAR szUnregisterProgIdInfo[] =
222 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
223 'I','n','f','o',0};
224 static const WCHAR szUnregisterTypeLibraries[] =
225 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
226 'L','i','b','r','a','r','i','e','s',0};
227 static const WCHAR szValidateProductID[] =
228 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
229 static const WCHAR szWriteEnvironmentStrings[] =
230 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
231 'S','t','r','i','n','g','s',0};
233 /* action handlers */
234 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
236 struct _actions {
237 LPCWSTR action;
238 STANDARDACTIONHANDLER handler;
242 /********************************************************
243 * helper functions
244 ********************************************************/
246 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
248 static const WCHAR Query_t[] =
249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
250 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
251 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
252 ' ','\'','%','s','\'',0};
253 MSIRECORD * row;
255 row = MSI_QueryGetRecord( package->db, Query_t, action );
256 if (!row)
257 return;
258 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
259 msiobj_release(&row->hdr);
262 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
263 UINT rc)
265 MSIRECORD * row;
266 static const WCHAR template_s[]=
267 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
268 '%','s', '.',0};
269 static const WCHAR template_e[]=
270 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
271 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
272 '%','i','.',0};
273 static const WCHAR format[] =
274 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
275 WCHAR message[1024];
276 WCHAR timet[0x100];
278 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
279 if (start)
280 sprintfW(message,template_s,timet,action);
281 else
282 sprintfW(message,template_e,timet,action,rc);
284 row = MSI_CreateRecord(1);
285 MSI_RecordSetStringW(row,1,message);
287 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
288 msiobj_release(&row->hdr);
291 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
293 LPCWSTR ptr,ptr2;
294 BOOL quote;
295 DWORD len;
296 LPWSTR prop = NULL, val = NULL;
298 if (!szCommandLine)
299 return ERROR_SUCCESS;
301 ptr = szCommandLine;
303 while (*ptr)
305 if (*ptr==' ')
307 ptr++;
308 continue;
311 TRACE("Looking at %s\n",debugstr_w(ptr));
313 ptr2 = strchrW(ptr,'=');
314 if (!ptr2)
316 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
317 break;
320 quote = FALSE;
322 len = ptr2-ptr;
323 prop = msi_alloc((len+1)*sizeof(WCHAR));
324 memcpy(prop,ptr,len*sizeof(WCHAR));
325 prop[len]=0;
326 ptr2++;
328 len = 0;
329 ptr = ptr2;
330 while (*ptr && (quote || (!quote && *ptr!=' ')))
332 if (*ptr == '"')
333 quote = !quote;
334 ptr++;
335 len++;
338 if (*ptr2=='"')
340 ptr2++;
341 len -= 2;
343 val = msi_alloc((len+1)*sizeof(WCHAR));
344 memcpy(val,ptr2,len*sizeof(WCHAR));
345 val[len] = 0;
347 if (lstrlenW(prop) > 0)
349 TRACE("Found commandline property (%s) = (%s)\n",
350 debugstr_w(prop), debugstr_w(val));
351 MSI_SetPropertyW(package,prop,val);
353 msi_free(val);
354 msi_free(prop);
357 return ERROR_SUCCESS;
361 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
363 LPCWSTR pc;
364 LPWSTR p, *ret = NULL;
365 UINT count = 0;
367 if (!str)
368 return ret;
370 /* count the number of substrings */
371 for ( pc = str, count = 0; pc; count++ )
373 pc = strchrW( pc, sep );
374 if (pc)
375 pc++;
378 /* allocate space for an array of substring pointers and the substrings */
379 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
380 (lstrlenW(str)+1) * sizeof(WCHAR) );
381 if (!ret)
382 return ret;
384 /* copy the string and set the pointers */
385 p = (LPWSTR) &ret[count+1];
386 lstrcpyW( p, str );
387 for( count = 0; (ret[count] = p); count++ )
389 p = strchrW( p, sep );
390 if (p)
391 *p++ = 0;
394 return ret;
397 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
399 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
400 LPWSTR prod_code, patch_product;
401 UINT ret;
403 prod_code = msi_dup_property( package, szProductCode );
404 patch_product = msi_get_suminfo_product( patch );
406 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
408 if ( strstrW( patch_product, prod_code ) )
409 ret = ERROR_SUCCESS;
410 else
411 ret = ERROR_FUNCTION_FAILED;
413 msi_free( patch_product );
414 msi_free( prod_code );
416 return ret;
419 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
420 MSIDATABASE *patch_db, LPCWSTR name )
422 UINT ret = ERROR_FUNCTION_FAILED;
423 IStorage *stg = NULL;
424 HRESULT r;
426 TRACE("%p %s\n", package, debugstr_w(name) );
428 if (*name++ != ':')
430 ERR("expected a colon in %s\n", debugstr_w(name));
431 return ERROR_FUNCTION_FAILED;
434 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
435 if (SUCCEEDED(r))
437 ret = msi_check_transform_applicable( package, stg );
438 if (ret == ERROR_SUCCESS)
439 msi_table_apply_transform( package->db, stg );
440 else
441 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
442 IStorage_Release( stg );
444 else
445 ERR("failed to open substorage %s\n", debugstr_w(name));
447 return ERROR_SUCCESS;
450 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
452 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
453 LPWSTR guid_list, *guids, product_code;
454 UINT i, ret = ERROR_FUNCTION_FAILED;
456 product_code = msi_dup_property( package, szProdCode );
457 if (!product_code)
459 /* FIXME: the property ProductCode should be written into the DB somewhere */
460 ERR("no product code to check\n");
461 return ERROR_SUCCESS;
464 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
465 guids = msi_split_string( guid_list, ';' );
466 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
468 if (!lstrcmpW( guids[i], product_code ))
469 ret = ERROR_SUCCESS;
471 msi_free( guids );
472 msi_free( guid_list );
473 msi_free( product_code );
475 return ret;
478 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
480 MSISUMMARYINFO *si;
481 LPWSTR str, *substorage;
482 UINT i, r = ERROR_SUCCESS;
484 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
485 if (!si)
486 return ERROR_FUNCTION_FAILED;
488 msi_check_patch_applicable( package, si );
490 /* enumerate the substorage */
491 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
492 substorage = msi_split_string( str, ';' );
493 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
494 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
495 msi_free( substorage );
496 msi_free( str );
498 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
500 msiobj_release( &si->hdr );
502 return r;
505 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
507 MSIDATABASE *patch_db = NULL;
508 UINT r;
510 TRACE("%p %s\n", package, debugstr_w( file ) );
512 /* FIXME:
513 * We probably want to make sure we only open a patch collection here.
514 * Patch collections (.msp) and databases (.msi) have different GUIDs
515 * but currently MSI_OpenDatabaseW will accept both.
517 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
518 if ( r != ERROR_SUCCESS )
520 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
521 return r;
524 msi_parse_patch_summary( package, patch_db );
527 * There might be a CAB file in the patch package,
528 * so append it to the list of storage to search for streams.
530 append_storage_to_db( package->db, patch_db->storage );
532 msiobj_release( &patch_db->hdr );
534 return ERROR_SUCCESS;
537 /* get the PATCH property, and apply all the patches it specifies */
538 static UINT msi_apply_patches( MSIPACKAGE *package )
540 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
541 LPWSTR patch_list, *patches;
542 UINT i, r = ERROR_SUCCESS;
544 patch_list = msi_dup_property( package, szPatch );
546 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
548 patches = msi_split_string( patch_list, ';' );
549 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
550 r = msi_apply_patch_package( package, patches[i] );
552 msi_free( patches );
553 msi_free( patch_list );
555 return r;
558 static UINT msi_apply_transforms( MSIPACKAGE *package )
560 static const WCHAR szTransforms[] = {
561 'T','R','A','N','S','F','O','R','M','S',0 };
562 LPWSTR xform_list, *xforms;
563 UINT i, r = ERROR_SUCCESS;
565 xform_list = msi_dup_property( package, szTransforms );
566 xforms = msi_split_string( xform_list, ';' );
568 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
570 if (xforms[i][0] == ':')
571 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
572 else
573 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
576 msi_free( xforms );
577 msi_free( xform_list );
579 return r;
582 static BOOL ui_sequence_exists( MSIPACKAGE *package )
584 MSIQUERY *view;
585 UINT rc;
587 static const WCHAR ExecSeqQuery [] =
588 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
589 '`','I','n','s','t','a','l','l',
590 'U','I','S','e','q','u','e','n','c','e','`',
591 ' ','W','H','E','R','E',' ',
592 '`','S','e','q','u','e','n','c','e','`',' ',
593 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
594 '`','S','e','q','u','e','n','c','e','`',0};
596 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
597 if (rc == ERROR_SUCCESS)
599 msiobj_release(&view->hdr);
600 return TRUE;
603 return FALSE;
606 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
608 LPWSTR p, db;
609 LPWSTR source, check;
610 DWORD len;
612 static const WCHAR szOriginalDatabase[] =
613 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
615 db = msi_dup_property( package, szOriginalDatabase );
616 if (!db)
617 return ERROR_OUTOFMEMORY;
619 p = strrchrW( db, '\\' );
620 if (!p)
622 p = strrchrW( db, '/' );
623 if (!p)
625 msi_free(db);
626 return ERROR_SUCCESS;
630 len = p - db + 2;
631 source = msi_alloc( len * sizeof(WCHAR) );
632 lstrcpynW( source, db, len );
634 check = msi_dup_property( package, cszSourceDir );
635 if (!check || replace)
636 MSI_SetPropertyW( package, cszSourceDir, source );
638 msi_free( check );
640 check = msi_dup_property( package, cszSOURCEDIR );
641 if (!check || replace)
642 MSI_SetPropertyW( package, cszSOURCEDIR, source );
644 msi_free( check );
645 msi_free( source );
646 msi_free( db );
648 return ERROR_SUCCESS;
651 /****************************************************
652 * TOP level entry points
653 *****************************************************/
655 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
656 LPCWSTR szCommandLine )
658 UINT rc;
659 BOOL ui = FALSE, ui_exists;
660 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
661 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
662 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
664 MSI_SetPropertyW(package, szAction, szInstall);
666 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
668 package->script->InWhatSequence = SEQUENCE_INSTALL;
670 if (szPackagePath)
672 LPWSTR p, dir;
673 LPCWSTR file;
675 dir = strdupW(szPackagePath);
676 p = strrchrW(dir, '\\');
677 if (p)
679 *(++p) = 0;
680 file = szPackagePath + (p - dir);
682 else
684 msi_free(dir);
685 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
686 GetCurrentDirectoryW(MAX_PATH, dir);
687 lstrcatW(dir, cszbs);
688 file = szPackagePath;
691 msi_free( package->PackagePath );
692 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
693 if (!package->PackagePath)
695 msi_free(dir);
696 return ERROR_OUTOFMEMORY;
699 lstrcpyW(package->PackagePath, dir);
700 lstrcatW(package->PackagePath, file);
701 msi_free(dir);
703 msi_set_sourcedir_props(package, FALSE);
706 msi_parse_command_line( package, szCommandLine );
708 msi_apply_transforms( package );
709 msi_apply_patches( package );
711 /* properties may have been added by a transform */
712 msi_clone_properties( package );
714 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
716 package->script->InWhatSequence |= SEQUENCE_UI;
717 rc = ACTION_ProcessUISequence(package);
718 ui = TRUE;
719 ui_exists = ui_sequence_exists(package);
720 if (rc == ERROR_SUCCESS || !ui_exists)
722 package->script->InWhatSequence |= SEQUENCE_EXEC;
723 rc = ACTION_ProcessExecSequence(package,ui_exists);
726 else
727 rc = ACTION_ProcessExecSequence(package,FALSE);
729 package->script->CurrentlyScripting= FALSE;
731 /* process the ending type action */
732 if (rc == ERROR_SUCCESS)
733 ACTION_PerformActionSequence(package,-1,ui);
734 else if (rc == ERROR_INSTALL_USEREXIT)
735 ACTION_PerformActionSequence(package,-2,ui);
736 else if (rc == ERROR_INSTALL_SUSPEND)
737 ACTION_PerformActionSequence(package,-4,ui);
738 else /* failed */
739 ACTION_PerformActionSequence(package,-3,ui);
741 /* finish up running custom actions */
742 ACTION_FinishCustomActions(package);
744 return rc;
747 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
749 UINT rc = ERROR_SUCCESS;
750 MSIRECORD * row = 0;
751 static const WCHAR ExecSeqQuery[] =
752 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
753 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
754 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
755 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
757 static const WCHAR UISeqQuery[] =
758 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
759 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
760 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
761 ' ', '=',' ','%','i',0};
763 if (UI)
764 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
765 else
766 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
768 if (row)
770 LPCWSTR action, cond;
772 TRACE("Running the actions\n");
774 /* check conditions */
775 cond = MSI_RecordGetString(row,2);
777 /* this is a hack to skip errors in the condition code */
778 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
779 goto end;
781 action = MSI_RecordGetString(row,1);
782 if (!action)
784 ERR("failed to fetch action\n");
785 rc = ERROR_FUNCTION_FAILED;
786 goto end;
789 if (UI)
790 rc = ACTION_PerformUIAction(package,action,-1);
791 else
792 rc = ACTION_PerformAction(package,action,-1,FALSE);
793 end:
794 msiobj_release(&row->hdr);
796 else
797 rc = ERROR_SUCCESS;
799 return rc;
802 typedef struct {
803 MSIPACKAGE* package;
804 BOOL UI;
805 } iterate_action_param;
807 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
809 iterate_action_param *iap= (iterate_action_param*)param;
810 UINT rc;
811 LPCWSTR cond, action;
813 action = MSI_RecordGetString(row,1);
814 if (!action)
816 ERR("Error is retrieving action name\n");
817 return ERROR_FUNCTION_FAILED;
820 /* check conditions */
821 cond = MSI_RecordGetString(row,2);
823 /* this is a hack to skip errors in the condition code */
824 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
826 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
827 return ERROR_SUCCESS;
830 if (iap->UI)
831 rc = ACTION_PerformUIAction(iap->package,action,-1);
832 else
833 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
835 msi_dialog_check_messages( NULL );
837 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
838 rc = iap->package->CurrentInstallState;
840 if (rc == ERROR_FUNCTION_NOT_CALLED)
841 rc = ERROR_SUCCESS;
843 if (rc != ERROR_SUCCESS)
844 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
846 return rc;
849 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
851 MSIQUERY * view;
852 UINT r;
853 static const WCHAR query[] =
854 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
855 '`','%','s','`',
856 ' ','W','H','E','R','E',' ',
857 '`','S','e','q','u','e','n','c','e','`',' ',
858 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
859 '`','S','e','q','u','e','n','c','e','`',0};
860 iterate_action_param iap;
863 * FIXME: probably should be checking UILevel in the
864 * ACTION_PerformUIAction/ACTION_PerformAction
865 * rather than saving the UI level here. Those
866 * two functions can be merged too.
868 iap.package = package;
869 iap.UI = TRUE;
871 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
873 r = MSI_OpenQuery( package->db, &view, query, szTable );
874 if (r == ERROR_SUCCESS)
876 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
877 msiobj_release(&view->hdr);
880 return r;
883 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
885 MSIQUERY * view;
886 UINT rc;
887 static const WCHAR ExecSeqQuery[] =
888 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
889 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
890 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
891 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
892 'O','R','D','E','R',' ', 'B','Y',' ',
893 '`','S','e','q','u','e','n','c','e','`',0 };
894 MSIRECORD * row = 0;
895 static const WCHAR IVQuery[] =
896 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
897 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
898 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
899 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
900 ' ','\'', 'I','n','s','t','a','l','l',
901 'V','a','l','i','d','a','t','e','\'', 0};
902 INT seq = 0;
903 iterate_action_param iap;
905 iap.package = package;
906 iap.UI = FALSE;
908 if (package->script->ExecuteSequenceRun)
910 TRACE("Execute Sequence already Run\n");
911 return ERROR_SUCCESS;
914 package->script->ExecuteSequenceRun = TRUE;
916 /* get the sequence number */
917 if (UIran)
919 row = MSI_QueryGetRecord(package->db, IVQuery);
920 if( !row )
921 return ERROR_FUNCTION_FAILED;
922 seq = MSI_RecordGetInteger(row,1);
923 msiobj_release(&row->hdr);
926 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
927 if (rc == ERROR_SUCCESS)
929 TRACE("Running the actions\n");
931 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
932 msiobj_release(&view->hdr);
935 return rc;
938 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
940 MSIQUERY * view;
941 UINT rc;
942 static const WCHAR ExecSeqQuery [] =
943 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
944 '`','I','n','s','t','a','l','l',
945 'U','I','S','e','q','u','e','n','c','e','`',
946 ' ','W','H','E','R','E',' ',
947 '`','S','e','q','u','e','n','c','e','`',' ',
948 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
949 '`','S','e','q','u','e','n','c','e','`',0};
950 iterate_action_param iap;
952 iap.package = package;
953 iap.UI = TRUE;
955 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
957 if (rc == ERROR_SUCCESS)
959 TRACE("Running the actions\n");
961 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
962 msiobj_release(&view->hdr);
965 return rc;
968 /********************************************************
969 * ACTION helper functions and functions that perform the actions
970 *******************************************************/
971 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
972 UINT* rc, UINT script, BOOL force )
974 BOOL ret=FALSE;
975 UINT arc;
977 arc = ACTION_CustomAction(package, action, script, force);
979 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
981 *rc = arc;
982 ret = TRUE;
984 return ret;
988 * A lot of actions are really important even if they don't do anything
989 * explicit... Lots of properties are set at the beginning of the installation
990 * CostFinalize does a bunch of work to translate the directories and such
992 * But until I get write access to the database that is hard, so I am going to
993 * hack it to see if I can get something to run.
995 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
997 UINT rc = ERROR_SUCCESS;
998 BOOL handled;
1000 TRACE("Performing action (%s)\n",debugstr_w(action));
1002 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1004 if (!handled)
1005 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1007 if (!handled)
1009 WARN("unhandled msi action %s\n",debugstr_w(action));
1010 rc = ERROR_FUNCTION_NOT_CALLED;
1013 return rc;
1016 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1018 UINT rc = ERROR_SUCCESS;
1019 BOOL handled = FALSE;
1021 TRACE("Performing action (%s)\n",debugstr_w(action));
1023 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1025 if (!handled)
1026 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1028 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1029 handled = TRUE;
1031 if (!handled)
1033 WARN("unhandled msi action %s\n",debugstr_w(action));
1034 rc = ERROR_FUNCTION_NOT_CALLED;
1037 return rc;
1042 * Actual Action Handlers
1045 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1047 MSIPACKAGE *package = (MSIPACKAGE*)param;
1048 LPCWSTR dir;
1049 LPWSTR full_path;
1050 MSIRECORD *uirow;
1051 MSIFOLDER *folder;
1053 dir = MSI_RecordGetString(row,1);
1054 if (!dir)
1056 ERR("Unable to get folder id\n");
1057 return ERROR_SUCCESS;
1060 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1061 if (!full_path)
1063 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1064 return ERROR_SUCCESS;
1067 TRACE("Folder is %s\n",debugstr_w(full_path));
1069 /* UI stuff */
1070 uirow = MSI_CreateRecord(1);
1071 MSI_RecordSetStringW(uirow,1,full_path);
1072 ui_actiondata(package,szCreateFolders,uirow);
1073 msiobj_release( &uirow->hdr );
1075 if (folder->State == 0)
1076 create_full_pathW(full_path);
1078 folder->State = 3;
1080 msi_free(full_path);
1081 return ERROR_SUCCESS;
1084 /* FIXME: probably should merge this with the above function */
1085 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1087 UINT rc = ERROR_SUCCESS;
1088 MSIFOLDER *folder;
1089 LPWSTR install_path;
1091 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1092 if (!install_path)
1093 return ERROR_FUNCTION_FAILED;
1095 /* create the path */
1096 if (folder->State == 0)
1098 create_full_pathW(install_path);
1099 folder->State = 2;
1101 msi_free(install_path);
1103 return rc;
1106 UINT msi_create_component_directories( MSIPACKAGE *package )
1108 MSICOMPONENT *comp;
1110 /* create all the folders required by the components are going to install */
1111 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1113 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1114 continue;
1115 msi_create_directory( package, comp->Directory );
1118 return ERROR_SUCCESS;
1122 * Also we cannot enable/disable components either, so for now I am just going
1123 * to do all the directories for all the components.
1125 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1127 static const WCHAR ExecSeqQuery[] =
1128 {'S','E','L','E','C','T',' ',
1129 '`','D','i','r','e','c','t','o','r','y','_','`',
1130 ' ','F','R','O','M',' ',
1131 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1132 UINT rc;
1133 MSIQUERY *view;
1135 /* create all the empty folders specified in the CreateFolder table */
1136 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1137 if (rc != ERROR_SUCCESS)
1138 return ERROR_SUCCESS;
1140 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1141 msiobj_release(&view->hdr);
1143 msi_create_component_directories( package );
1145 return rc;
1148 static UINT load_component( MSIRECORD *row, LPVOID param )
1150 MSIPACKAGE *package = param;
1151 MSICOMPONENT *comp;
1153 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1154 if (!comp)
1155 return ERROR_FUNCTION_FAILED;
1157 list_add_tail( &package->components, &comp->entry );
1159 /* fill in the data */
1160 comp->Component = msi_dup_record_field( row, 1 );
1162 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1164 comp->ComponentId = msi_dup_record_field( row, 2 );
1165 comp->Directory = msi_dup_record_field( row, 3 );
1166 comp->Attributes = MSI_RecordGetInteger(row,4);
1167 comp->Condition = msi_dup_record_field( row, 5 );
1168 comp->KeyPath = msi_dup_record_field( row, 6 );
1170 comp->Installed = INSTALLSTATE_UNKNOWN;
1171 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1173 return ERROR_SUCCESS;
1176 static UINT load_all_components( MSIPACKAGE *package )
1178 static const WCHAR query[] = {
1179 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1180 '`','C','o','m','p','o','n','e','n','t','`',0 };
1181 MSIQUERY *view;
1182 UINT r;
1184 if (!list_empty(&package->components))
1185 return ERROR_SUCCESS;
1187 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1188 if (r != ERROR_SUCCESS)
1189 return r;
1191 r = MSI_IterateRecords(view, NULL, load_component, package);
1192 msiobj_release(&view->hdr);
1193 return r;
1196 typedef struct {
1197 MSIPACKAGE *package;
1198 MSIFEATURE *feature;
1199 } _ilfs;
1201 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1203 ComponentList *cl;
1205 cl = msi_alloc( sizeof (*cl) );
1206 if ( !cl )
1207 return ERROR_NOT_ENOUGH_MEMORY;
1208 cl->component = comp;
1209 list_add_tail( &feature->Components, &cl->entry );
1211 return ERROR_SUCCESS;
1214 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1216 FeatureList *fl;
1218 fl = msi_alloc( sizeof(*fl) );
1219 if ( !fl )
1220 return ERROR_NOT_ENOUGH_MEMORY;
1221 fl->feature = child;
1222 list_add_tail( &parent->Children, &fl->entry );
1224 return ERROR_SUCCESS;
1227 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1229 _ilfs* ilfs= (_ilfs*)param;
1230 LPCWSTR component;
1231 MSICOMPONENT *comp;
1233 component = MSI_RecordGetString(row,1);
1235 /* check to see if the component is already loaded */
1236 comp = get_loaded_component( ilfs->package, component );
1237 if (!comp)
1239 ERR("unknown component %s\n", debugstr_w(component));
1240 return ERROR_FUNCTION_FAILED;
1243 add_feature_component( ilfs->feature, comp );
1244 comp->Enabled = TRUE;
1246 return ERROR_SUCCESS;
1249 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1251 MSIFEATURE *feature;
1253 if ( !name )
1254 return NULL;
1256 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1258 if ( !lstrcmpW( feature->Feature, name ) )
1259 return feature;
1262 return NULL;
1265 static UINT load_feature(MSIRECORD * row, LPVOID param)
1267 MSIPACKAGE* package = (MSIPACKAGE*)param;
1268 MSIFEATURE* feature;
1269 static const WCHAR Query1[] =
1270 {'S','E','L','E','C','T',' ',
1271 '`','C','o','m','p','o','n','e','n','t','_','`',
1272 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1273 'C','o','m','p','o','n','e','n','t','s','`',' ',
1274 'W','H','E','R','E',' ',
1275 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1276 MSIQUERY * view;
1277 UINT rc;
1278 _ilfs ilfs;
1280 /* fill in the data */
1282 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1283 if (!feature)
1284 return ERROR_NOT_ENOUGH_MEMORY;
1286 list_init( &feature->Children );
1287 list_init( &feature->Components );
1289 feature->Feature = msi_dup_record_field( row, 1 );
1291 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1293 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1294 feature->Title = msi_dup_record_field( row, 3 );
1295 feature->Description = msi_dup_record_field( row, 4 );
1297 if (!MSI_RecordIsNull(row,5))
1298 feature->Display = MSI_RecordGetInteger(row,5);
1300 feature->Level= MSI_RecordGetInteger(row,6);
1301 feature->Directory = msi_dup_record_field( row, 7 );
1302 feature->Attributes = MSI_RecordGetInteger(row,8);
1304 feature->Installed = INSTALLSTATE_UNKNOWN;
1305 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1307 list_add_tail( &package->features, &feature->entry );
1309 /* load feature components */
1311 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1312 if (rc != ERROR_SUCCESS)
1313 return ERROR_SUCCESS;
1315 ilfs.package = package;
1316 ilfs.feature = feature;
1318 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1319 msiobj_release(&view->hdr);
1321 return ERROR_SUCCESS;
1324 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1326 MSIPACKAGE* package = (MSIPACKAGE*)param;
1327 MSIFEATURE *parent, *child;
1329 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1330 if (!child)
1331 return ERROR_FUNCTION_FAILED;
1333 if (!child->Feature_Parent)
1334 return ERROR_SUCCESS;
1336 parent = find_feature_by_name( package, child->Feature_Parent );
1337 if (!parent)
1338 return ERROR_FUNCTION_FAILED;
1340 add_feature_child( parent, child );
1341 return ERROR_SUCCESS;
1344 static UINT load_all_features( MSIPACKAGE *package )
1346 static const WCHAR query[] = {
1347 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1348 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1349 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1350 MSIQUERY *view;
1351 UINT r;
1353 if (!list_empty(&package->features))
1354 return ERROR_SUCCESS;
1356 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1357 if (r != ERROR_SUCCESS)
1358 return r;
1360 r = MSI_IterateRecords( view, NULL, load_feature, package );
1361 if (r != ERROR_SUCCESS)
1362 return r;
1364 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1365 msiobj_release( &view->hdr );
1367 return r;
1370 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1372 if (!p)
1373 return p;
1374 p = strchrW(p, ch);
1375 if (!p)
1376 return p;
1377 *p = 0;
1378 return p+1;
1381 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1383 static const WCHAR query[] = {
1384 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1385 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1386 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1387 MSIQUERY *view = NULL;
1388 MSIRECORD *row = NULL;
1389 UINT r;
1391 TRACE("%s\n", debugstr_w(file->File));
1393 r = MSI_OpenQuery(package->db, &view, query, file->File);
1394 if (r != ERROR_SUCCESS)
1395 goto done;
1397 r = MSI_ViewExecute(view, NULL);
1398 if (r != ERROR_SUCCESS)
1399 goto done;
1401 r = MSI_ViewFetch(view, &row);
1402 if (r != ERROR_SUCCESS)
1403 goto done;
1405 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1406 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1407 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1408 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1409 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1411 done:
1412 if (view) msiobj_release(&view->hdr);
1413 if (row) msiobj_release(&row->hdr);
1414 return r;
1417 static UINT load_file(MSIRECORD *row, LPVOID param)
1419 MSIPACKAGE* package = (MSIPACKAGE*)param;
1420 LPCWSTR component;
1421 MSIFILE *file;
1423 /* fill in the data */
1425 file = msi_alloc_zero( sizeof (MSIFILE) );
1426 if (!file)
1427 return ERROR_NOT_ENOUGH_MEMORY;
1429 file->File = msi_dup_record_field( row, 1 );
1431 component = MSI_RecordGetString( row, 2 );
1432 file->Component = get_loaded_component( package, component );
1434 if (!file->Component)
1435 ERR("Unfound Component %s\n",debugstr_w(component));
1437 file->FileName = msi_dup_record_field( row, 3 );
1438 reduce_to_longfilename( file->FileName );
1440 file->ShortName = msi_dup_record_field( row, 3 );
1441 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1443 file->FileSize = MSI_RecordGetInteger( row, 4 );
1444 file->Version = msi_dup_record_field( row, 5 );
1445 file->Language = msi_dup_record_field( row, 6 );
1446 file->Attributes = MSI_RecordGetInteger( row, 7 );
1447 file->Sequence = MSI_RecordGetInteger( row, 8 );
1449 file->state = msifs_invalid;
1451 /* if the compressed bits are not set in the file attributes,
1452 * then read the information from the package word count property
1454 if (file->Attributes & msidbFileAttributesCompressed)
1456 file->IsCompressed = TRUE;
1458 else if (file->Attributes & msidbFileAttributesNoncompressed)
1460 file->IsCompressed = FALSE;
1462 else
1464 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1467 load_file_hash(package, file);
1469 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1471 list_add_tail( &package->files, &file->entry );
1473 return ERROR_SUCCESS;
1476 static UINT load_all_files(MSIPACKAGE *package)
1478 MSIQUERY * view;
1479 UINT rc;
1480 static const WCHAR Query[] =
1481 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1482 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1483 '`','S','e','q','u','e','n','c','e','`', 0};
1485 if (!list_empty(&package->files))
1486 return ERROR_SUCCESS;
1488 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1489 if (rc != ERROR_SUCCESS)
1490 return ERROR_SUCCESS;
1492 rc = MSI_IterateRecords(view, NULL, load_file, package);
1493 msiobj_release(&view->hdr);
1495 return ERROR_SUCCESS;
1498 static UINT load_folder( MSIRECORD *row, LPVOID param )
1500 MSIPACKAGE *package = param;
1501 static const WCHAR szDot[] = { '.',0 };
1502 static WCHAR szEmpty[] = { 0 };
1503 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1504 MSIFOLDER *folder;
1506 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1507 if (!folder)
1508 return ERROR_NOT_ENOUGH_MEMORY;
1510 folder->Directory = msi_dup_record_field( row, 1 );
1512 TRACE("%s\n", debugstr_w(folder->Directory));
1514 p = msi_dup_record_field(row, 3);
1516 /* split src and target dir */
1517 tgt_short = p;
1518 src_short = folder_split_path( p, ':' );
1520 /* split the long and short paths */
1521 tgt_long = folder_split_path( tgt_short, '|' );
1522 src_long = folder_split_path( src_short, '|' );
1524 /* check for no-op dirs */
1525 if (!lstrcmpW(szDot, tgt_short))
1526 tgt_short = szEmpty;
1527 if (!lstrcmpW(szDot, src_short))
1528 src_short = szEmpty;
1530 if (!tgt_long)
1531 tgt_long = tgt_short;
1533 if (!src_short) {
1534 src_short = tgt_short;
1535 src_long = tgt_long;
1538 if (!src_long)
1539 src_long = src_short;
1541 /* FIXME: use the target short path too */
1542 folder->TargetDefault = strdupW(tgt_long);
1543 folder->SourceShortPath = strdupW(src_short);
1544 folder->SourceLongPath = strdupW(src_long);
1545 msi_free(p);
1547 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1548 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1549 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1551 folder->Parent = msi_dup_record_field( row, 2 );
1553 folder->Property = msi_dup_property( package, folder->Directory );
1555 list_add_tail( &package->folders, &folder->entry );
1557 TRACE("returning %p\n", folder);
1559 return ERROR_SUCCESS;
1562 static UINT load_all_folders( MSIPACKAGE *package )
1564 static const WCHAR query[] = {
1565 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1566 '`','D','i','r','e','c','t','o','r','y','`',0 };
1567 MSIQUERY *view;
1568 UINT r;
1570 if (!list_empty(&package->folders))
1571 return ERROR_SUCCESS;
1573 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1574 if (r != ERROR_SUCCESS)
1575 return r;
1577 r = MSI_IterateRecords(view, NULL, load_folder, package);
1578 msiobj_release(&view->hdr);
1579 return r;
1583 * I am not doing any of the costing functionality yet.
1584 * Mostly looking at doing the Component and Feature loading
1586 * The native MSI does A LOT of modification to tables here. Mostly adding
1587 * a lot of temporary columns to the Feature and Component tables.
1589 * note: Native msi also tracks the short filename. But I am only going to
1590 * track the long ones. Also looking at this directory table
1591 * it appears that the directory table does not get the parents
1592 * resolved base on property only based on their entries in the
1593 * directory table.
1595 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1597 static const WCHAR szCosting[] =
1598 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1599 static const WCHAR szZero[] = { '0', 0 };
1601 MSI_SetPropertyW(package, szCosting, szZero);
1602 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1604 load_all_components( package );
1605 load_all_features( package );
1606 load_all_files( package );
1607 load_all_folders( package );
1609 return ERROR_SUCCESS;
1612 static UINT execute_script(MSIPACKAGE *package, UINT script )
1614 UINT i;
1615 UINT rc = ERROR_SUCCESS;
1617 TRACE("Executing Script %i\n",script);
1619 if (!package->script)
1621 ERR("no script!\n");
1622 return ERROR_FUNCTION_FAILED;
1625 for (i = 0; i < package->script->ActionCount[script]; i++)
1627 LPWSTR action;
1628 action = package->script->Actions[script][i];
1629 ui_actionstart(package, action);
1630 TRACE("Executing Action (%s)\n",debugstr_w(action));
1631 rc = ACTION_PerformAction(package, action, script, TRUE);
1632 if (rc != ERROR_SUCCESS)
1633 break;
1635 msi_free_action_script(package, script);
1636 return rc;
1639 static UINT ACTION_FileCost(MSIPACKAGE *package)
1641 return ERROR_SUCCESS;
1644 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1646 MSICOMPONENT *comp;
1648 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1650 INSTALLSTATE res;
1652 if (!comp->ComponentId)
1653 continue;
1655 res = MsiGetComponentPathW( package->ProductCode,
1656 comp->ComponentId, NULL, NULL);
1657 if (res < 0)
1658 res = INSTALLSTATE_ABSENT;
1659 comp->Installed = res;
1663 /* scan for and update current install states */
1664 static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1666 MSICOMPONENT *comp;
1667 MSIFEATURE *feature;
1669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1671 ComponentList *cl;
1672 INSTALLSTATE res = INSTALLSTATE_ABSENT;
1674 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1676 comp= cl->component;
1678 if (!comp->ComponentId)
1680 res = INSTALLSTATE_ABSENT;
1681 break;
1684 if (res == INSTALLSTATE_ABSENT)
1685 res = comp->Installed;
1686 else
1688 if (res == comp->Installed)
1689 continue;
1691 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
1692 res != INSTALLSTATE_SOURCE)
1694 res = INSTALLSTATE_INCOMPLETE;
1698 feature->Installed = res;
1702 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1703 INSTALLSTATE state)
1705 static const WCHAR all[]={'A','L','L',0};
1706 LPWSTR override;
1707 MSIFEATURE *feature;
1709 override = msi_dup_property( package, property );
1710 if (!override)
1711 return FALSE;
1713 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1715 if (strcmpiW(override,all)==0)
1716 msi_feature_set_state( feature, state );
1717 else
1719 LPWSTR ptr = override;
1720 LPWSTR ptr2 = strchrW(override,',');
1722 while (ptr)
1724 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1725 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1727 msi_feature_set_state( feature, state );
1728 break;
1730 if (ptr2)
1732 ptr=ptr2+1;
1733 ptr2 = strchrW(ptr,',');
1735 else
1736 break;
1740 msi_free(override);
1742 return TRUE;
1745 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1747 int install_level;
1748 static const WCHAR szlevel[] =
1749 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1750 static const WCHAR szAddLocal[] =
1751 {'A','D','D','L','O','C','A','L',0};
1752 static const WCHAR szAddSource[] =
1753 {'A','D','D','S','O','U','R','C','E',0};
1754 static const WCHAR szRemove[] =
1755 {'R','E','M','O','V','E',0};
1756 static const WCHAR szReinstall[] =
1757 {'R','E','I','N','S','T','A','L','L',0};
1758 BOOL override = FALSE;
1759 MSICOMPONENT* component;
1760 MSIFEATURE *feature;
1763 /* I do not know if this is where it should happen.. but */
1765 TRACE("Checking Install Level\n");
1767 install_level = msi_get_property_int( package, szlevel, 1 );
1769 /* ok here is the _real_ rub
1770 * all these activation/deactivation things happen in order and things
1771 * later on the list override things earlier on the list.
1772 * 1) INSTALLLEVEL processing
1773 * 2) ADDLOCAL
1774 * 3) REMOVE
1775 * 4) ADDSOURCE
1776 * 5) ADDDEFAULT
1777 * 6) REINSTALL
1778 * 7) COMPADDLOCAL
1779 * 8) COMPADDSOURCE
1780 * 9) FILEADDLOCAL
1781 * 10) FILEADDSOURCE
1782 * 11) FILEADDDEFAULT
1783 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1784 * ignored for all the features. seems strange, especially since it is not
1785 * documented anywhere, but it is how it works.
1787 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1788 * REMOVE are the big ones, since we don't handle administrative installs
1789 * yet anyway.
1791 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1792 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1793 override |= process_state_property(package,szAddSource,INSTALLSTATE_SOURCE);
1794 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1796 if (!override)
1798 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1800 BOOL feature_state = ((feature->Level > 0) &&
1801 (feature->Level <= install_level));
1803 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1805 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1806 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1807 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1808 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1809 else
1810 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1814 /* disable child features of unselected parent features */
1815 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1817 FeatureList *fl;
1819 if (feature->Level > 0 && feature->Level <= install_level)
1820 continue;
1822 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1823 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1826 else
1828 /* set the Preselected Property */
1829 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1830 static const WCHAR szOne[] = { '1', 0 };
1832 MSI_SetPropertyW(package,szPreselected,szOne);
1836 * now we want to enable or disable components base on feature
1839 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1841 ComponentList *cl;
1843 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
1844 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1846 /* features with components that have compressed files are made local */
1847 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1849 if (cl->component->Enabled &&
1850 cl->component->ForceLocalState &&
1851 feature->Action == INSTALLSTATE_SOURCE)
1853 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1854 break;
1858 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1860 component = cl->component;
1862 if (!component->Enabled)
1863 continue;
1865 switch (feature->Action)
1867 case INSTALLSTATE_ABSENT:
1868 component->anyAbsent = 1;
1869 break;
1870 case INSTALLSTATE_ADVERTISED:
1871 component->hasAdvertiseFeature = 1;
1872 break;
1873 case INSTALLSTATE_SOURCE:
1874 component->hasSourceFeature = 1;
1875 break;
1876 case INSTALLSTATE_LOCAL:
1877 component->hasLocalFeature = 1;
1878 break;
1879 case INSTALLSTATE_DEFAULT:
1880 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1881 component->hasAdvertiseFeature = 1;
1882 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1883 component->hasSourceFeature = 1;
1884 else
1885 component->hasLocalFeature = 1;
1886 break;
1887 default:
1888 break;
1893 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1895 /* if the component isn't enabled, leave it alone */
1896 if (!component->Enabled)
1897 continue;
1899 /* check if it's local or source */
1900 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1901 (component->hasLocalFeature || component->hasSourceFeature))
1903 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1904 !component->ForceLocalState)
1905 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1906 else
1907 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1908 continue;
1911 /* if any feature is local, the component must be local too */
1912 if (component->hasLocalFeature)
1914 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1915 continue;
1918 if (component->hasSourceFeature)
1920 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1921 continue;
1924 if (component->hasAdvertiseFeature)
1926 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1927 continue;
1930 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1931 if (component->anyAbsent)
1932 msi_component_set_state(component, INSTALLSTATE_ABSENT);
1935 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1937 if (component->Action == INSTALLSTATE_DEFAULT)
1939 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1940 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1943 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1944 debugstr_w(component->Component), component->Installed, component->Action);
1948 return ERROR_SUCCESS;
1951 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1953 MSIPACKAGE *package = (MSIPACKAGE*)param;
1954 LPCWSTR name;
1955 LPWSTR path;
1956 MSIFOLDER *f;
1958 name = MSI_RecordGetString(row,1);
1960 f = get_loaded_folder(package, name);
1961 if (!f) return ERROR_SUCCESS;
1963 /* reset the ResolvedTarget */
1964 msi_free(f->ResolvedTarget);
1965 f->ResolvedTarget = NULL;
1967 /* This helper function now does ALL the work */
1968 TRACE("Dir %s ...\n",debugstr_w(name));
1969 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1970 TRACE("resolves to %s\n",debugstr_w(path));
1971 msi_free(path);
1973 return ERROR_SUCCESS;
1976 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1978 MSIPACKAGE *package = (MSIPACKAGE*)param;
1979 LPCWSTR name;
1980 MSIFEATURE *feature;
1982 name = MSI_RecordGetString( row, 1 );
1984 feature = get_loaded_feature( package, name );
1985 if (!feature)
1986 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1987 else
1989 LPCWSTR Condition;
1990 Condition = MSI_RecordGetString(row,3);
1992 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1994 int level = MSI_RecordGetInteger(row,2);
1995 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1996 feature->Level = level;
1999 return ERROR_SUCCESS;
2002 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
2004 static const WCHAR name_fmt[] =
2005 {'%','u','.','%','u','.','%','u','.','%','u',0};
2006 static WCHAR name[] = {'\\',0};
2007 VS_FIXEDFILEINFO *lpVer;
2008 WCHAR filever[0x100];
2009 LPVOID version;
2010 DWORD versize;
2011 DWORD handle;
2012 UINT sz;
2014 TRACE("%s\n", debugstr_w(filename));
2016 versize = GetFileVersionInfoSizeW( filename, &handle );
2017 if (!versize)
2018 return NULL;
2020 version = msi_alloc( versize );
2021 GetFileVersionInfoW( filename, 0, versize, version );
2023 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2025 msi_free( version );
2026 return NULL;
2029 sprintfW( filever, name_fmt,
2030 HIWORD(lpVer->dwFileVersionMS),
2031 LOWORD(lpVer->dwFileVersionMS),
2032 HIWORD(lpVer->dwFileVersionLS),
2033 LOWORD(lpVer->dwFileVersionLS));
2035 msi_free( version );
2037 return strdupW( filever );
2040 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2042 LPWSTR file_version;
2043 MSIFILE *file;
2045 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2047 MSICOMPONENT* comp = file->Component;
2048 LPWSTR p;
2050 if (!comp)
2051 continue;
2053 if (file->IsCompressed)
2054 comp->ForceLocalState = TRUE;
2056 /* calculate target */
2057 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2059 msi_free(file->TargetPath);
2061 TRACE("file %s is named %s\n",
2062 debugstr_w(file->File), debugstr_w(file->FileName));
2064 file->TargetPath = build_directory_name(2, p, file->FileName);
2066 msi_free(p);
2068 TRACE("file %s resolves to %s\n",
2069 debugstr_w(file->File), debugstr_w(file->TargetPath));
2071 /* don't check files of components that aren't installed */
2072 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2073 comp->Installed == INSTALLSTATE_ABSENT)
2075 file->state = msifs_missing; /* assume files are missing */
2076 continue;
2079 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2081 file->state = msifs_missing;
2082 comp->Cost += file->FileSize;
2083 comp->Installed = INSTALLSTATE_INCOMPLETE;
2084 continue;
2087 if (file->Version &&
2088 (file_version = msi_get_disk_file_version( file->TargetPath )))
2090 TRACE("new %s old %s\n", debugstr_w(file->Version),
2091 debugstr_w(file_version));
2092 /* FIXME: seems like a bad way to compare version numbers */
2093 if (lstrcmpiW(file_version, file->Version)<0)
2095 file->state = msifs_overwrite;
2096 comp->Cost += file->FileSize;
2097 comp->Installed = INSTALLSTATE_INCOMPLETE;
2099 else
2100 file->state = msifs_present;
2101 msi_free( file_version );
2103 else
2104 file->state = msifs_present;
2107 return ERROR_SUCCESS;
2111 * A lot is done in this function aside from just the costing.
2112 * The costing needs to be implemented at some point but for now I am going
2113 * to focus on the directory building
2116 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2118 static const WCHAR ExecSeqQuery[] =
2119 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2120 '`','D','i','r','e','c','t','o','r','y','`',0};
2121 static const WCHAR ConditionQuery[] =
2122 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2123 '`','C','o','n','d','i','t','i','o','n','`',0};
2124 static const WCHAR szCosting[] =
2125 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2126 static const WCHAR szlevel[] =
2127 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2128 static const WCHAR szOne[] = { '1', 0 };
2129 MSICOMPONENT *comp;
2130 UINT rc;
2131 MSIQUERY * view;
2132 LPWSTR level;
2134 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2135 return ERROR_SUCCESS;
2137 TRACE("Building Directory properties\n");
2139 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2140 if (rc == ERROR_SUCCESS)
2142 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2143 package);
2144 msiobj_release(&view->hdr);
2147 /* read components states from the registry */
2148 ACTION_GetComponentInstallStates(package);
2150 TRACE("File calculations\n");
2151 msi_check_file_install_states( package );
2153 TRACE("Evaluating Condition Table\n");
2155 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2156 if (rc == ERROR_SUCCESS)
2158 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2159 package);
2160 msiobj_release(&view->hdr);
2163 TRACE("Enabling or Disabling Components\n");
2164 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2166 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2168 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2169 comp->Enabled = FALSE;
2173 MSI_SetPropertyW(package,szCosting,szOne);
2174 /* set default run level if not set */
2175 level = msi_dup_property( package, szlevel );
2176 if (!level)
2177 MSI_SetPropertyW(package,szlevel, szOne);
2178 msi_free(level);
2180 ACTION_UpdateFeatureInstallStates(package);
2182 return MSI_SetFeatureStates(package);
2185 /* OK this value is "interpreted" and then formatted based on the
2186 first few characters */
2187 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2188 DWORD *size)
2190 LPSTR data = NULL;
2192 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2194 if (value[1]=='x')
2196 LPWSTR ptr;
2197 CHAR byte[5];
2198 LPWSTR deformated = NULL;
2199 int count;
2201 deformat_string(package, &value[2], &deformated);
2203 /* binary value type */
2204 ptr = deformated;
2205 *type = REG_BINARY;
2206 if (strlenW(ptr)%2)
2207 *size = (strlenW(ptr)/2)+1;
2208 else
2209 *size = strlenW(ptr)/2;
2211 data = msi_alloc(*size);
2213 byte[0] = '0';
2214 byte[1] = 'x';
2215 byte[4] = 0;
2216 count = 0;
2217 /* if uneven pad with a zero in front */
2218 if (strlenW(ptr)%2)
2220 byte[2]= '0';
2221 byte[3]= *ptr;
2222 ptr++;
2223 data[count] = (BYTE)strtol(byte,NULL,0);
2224 count ++;
2225 TRACE("Uneven byte count\n");
2227 while (*ptr)
2229 byte[2]= *ptr;
2230 ptr++;
2231 byte[3]= *ptr;
2232 ptr++;
2233 data[count] = (BYTE)strtol(byte,NULL,0);
2234 count ++;
2236 msi_free(deformated);
2238 TRACE("Data %i bytes(%i)\n",*size,count);
2240 else
2242 LPWSTR deformated;
2243 LPWSTR p;
2244 DWORD d = 0;
2245 deformat_string(package, &value[1], &deformated);
2247 *type=REG_DWORD;
2248 *size = sizeof(DWORD);
2249 data = msi_alloc(*size);
2250 p = deformated;
2251 if (*p == '-')
2252 p++;
2253 while (*p)
2255 if ( (*p < '0') || (*p > '9') )
2256 break;
2257 d *= 10;
2258 d += (*p - '0');
2259 p++;
2261 if (deformated[0] == '-')
2262 d = -d;
2263 *(LPDWORD)data = d;
2264 TRACE("DWORD %i\n",*(LPDWORD)data);
2266 msi_free(deformated);
2269 else
2271 static const WCHAR szMulti[] = {'[','~',']',0};
2272 LPCWSTR ptr;
2273 *type=REG_SZ;
2275 if (value[0]=='#')
2277 if (value[1]=='%')
2279 ptr = &value[2];
2280 *type=REG_EXPAND_SZ;
2282 else
2283 ptr = &value[1];
2285 else
2286 ptr=value;
2288 if (strstrW(value,szMulti))
2289 *type = REG_MULTI_SZ;
2291 /* remove initial delimiter */
2292 if (!strncmpW(value, szMulti, 3))
2293 ptr = value + 3;
2295 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2297 /* add double NULL terminator */
2298 if (*type == REG_MULTI_SZ)
2300 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2301 data = msi_realloc_zero(data, *size);
2304 return data;
2307 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2309 MSIPACKAGE *package = (MSIPACKAGE*)param;
2310 static const WCHAR szHCR[] =
2311 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2312 'R','O','O','T','\\',0};
2313 static const WCHAR szHCU[] =
2314 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2315 'U','S','E','R','\\',0};
2316 static const WCHAR szHLM[] =
2317 {'H','K','E','Y','_','L','O','C','A','L','_',
2318 'M','A','C','H','I','N','E','\\',0};
2319 static const WCHAR szHU[] =
2320 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2322 LPSTR value_data = NULL;
2323 HKEY root_key, hkey;
2324 DWORD type,size;
2325 LPWSTR deformated;
2326 LPCWSTR szRoot, component, name, key, value;
2327 MSICOMPONENT *comp;
2328 MSIRECORD * uirow;
2329 LPWSTR uikey;
2330 INT root;
2331 BOOL check_first = FALSE;
2332 UINT rc;
2334 ui_progress(package,2,0,0,0);
2336 value = NULL;
2337 key = NULL;
2338 uikey = NULL;
2339 name = NULL;
2341 component = MSI_RecordGetString(row, 6);
2342 comp = get_loaded_component(package,component);
2343 if (!comp)
2344 return ERROR_SUCCESS;
2346 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2348 TRACE("Skipping write due to disabled component %s\n",
2349 debugstr_w(component));
2351 comp->Action = comp->Installed;
2353 return ERROR_SUCCESS;
2356 comp->Action = INSTALLSTATE_LOCAL;
2358 name = MSI_RecordGetString(row, 4);
2359 if( MSI_RecordIsNull(row,5) && name )
2361 /* null values can have special meanings */
2362 if (name[0]=='-' && name[1] == 0)
2363 return ERROR_SUCCESS;
2364 else if ((name[0]=='+' && name[1] == 0) ||
2365 (name[0] == '*' && name[1] == 0))
2366 name = NULL;
2367 check_first = TRUE;
2370 root = MSI_RecordGetInteger(row,2);
2371 key = MSI_RecordGetString(row, 3);
2373 /* get the root key */
2374 switch (root)
2376 case -1:
2378 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2379 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2380 if (all_users && all_users[0] == '1')
2382 root_key = HKEY_LOCAL_MACHINE;
2383 szRoot = szHLM;
2385 else
2387 root_key = HKEY_CURRENT_USER;
2388 szRoot = szHCU;
2390 msi_free(all_users);
2392 break;
2393 case 0: root_key = HKEY_CLASSES_ROOT;
2394 szRoot = szHCR;
2395 break;
2396 case 1: root_key = HKEY_CURRENT_USER;
2397 szRoot = szHCU;
2398 break;
2399 case 2: root_key = HKEY_LOCAL_MACHINE;
2400 szRoot = szHLM;
2401 break;
2402 case 3: root_key = HKEY_USERS;
2403 szRoot = szHU;
2404 break;
2405 default:
2406 ERR("Unknown root %i\n",root);
2407 root_key=NULL;
2408 szRoot = NULL;
2409 break;
2411 if (!root_key)
2412 return ERROR_SUCCESS;
2414 deformat_string(package, key , &deformated);
2415 size = strlenW(deformated) + strlenW(szRoot) + 1;
2416 uikey = msi_alloc(size*sizeof(WCHAR));
2417 strcpyW(uikey,szRoot);
2418 strcatW(uikey,deformated);
2420 if (RegCreateKeyW( root_key, deformated, &hkey))
2422 ERR("Could not create key %s\n",debugstr_w(deformated));
2423 msi_free(deformated);
2424 msi_free(uikey);
2425 return ERROR_SUCCESS;
2427 msi_free(deformated);
2429 value = MSI_RecordGetString(row,5);
2430 if (value)
2431 value_data = parse_value(package, value, &type, &size);
2432 else
2434 static const WCHAR szEmpty[] = {0};
2435 value_data = (LPSTR)strdupW(szEmpty);
2436 size = sizeof(szEmpty);
2437 type = REG_SZ;
2440 deformat_string(package, name, &deformated);
2442 if (!check_first)
2444 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2445 debugstr_w(uikey));
2446 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2448 else
2450 DWORD sz = 0;
2451 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2452 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2454 TRACE("value %s of %s checked already exists\n",
2455 debugstr_w(deformated), debugstr_w(uikey));
2457 else
2459 TRACE("Checked and setting value %s of %s\n",
2460 debugstr_w(deformated), debugstr_w(uikey));
2461 if (deformated || size)
2462 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2465 RegCloseKey(hkey);
2467 uirow = MSI_CreateRecord(3);
2468 MSI_RecordSetStringW(uirow,2,deformated);
2469 MSI_RecordSetStringW(uirow,1,uikey);
2471 if (type == REG_SZ)
2472 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2473 else
2474 MSI_RecordSetStringW(uirow,3,value);
2476 ui_actiondata(package,szWriteRegistryValues,uirow);
2477 msiobj_release( &uirow->hdr );
2479 msi_free(value_data);
2480 msi_free(deformated);
2481 msi_free(uikey);
2483 return ERROR_SUCCESS;
2486 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2488 UINT rc;
2489 MSIQUERY * view;
2490 static const WCHAR ExecSeqQuery[] =
2491 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2492 '`','R','e','g','i','s','t','r','y','`',0 };
2494 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2495 if (rc != ERROR_SUCCESS)
2496 return ERROR_SUCCESS;
2498 /* increment progress bar each time action data is sent */
2499 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2501 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2503 msiobj_release(&view->hdr);
2504 return rc;
2507 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2509 package->script->CurrentlyScripting = TRUE;
2511 return ERROR_SUCCESS;
2515 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2517 MSICOMPONENT *comp;
2518 DWORD progress = 0;
2519 DWORD total = 0;
2520 static const WCHAR q1[]=
2521 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2522 '`','R','e','g','i','s','t','r','y','`',0};
2523 UINT rc;
2524 MSIQUERY * view;
2525 MSIFEATURE *feature;
2526 MSIFILE *file;
2528 TRACE("InstallValidate\n");
2530 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2531 if (rc == ERROR_SUCCESS)
2533 MSI_IterateRecords( view, &progress, NULL, package );
2534 msiobj_release( &view->hdr );
2535 total += progress * REG_PROGRESS_VALUE;
2538 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2539 total += COMPONENT_PROGRESS_VALUE;
2541 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2542 total += file->FileSize;
2544 ui_progress(package,0,total,0,0);
2546 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2548 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2549 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2550 feature->ActionRequest);
2553 return ERROR_SUCCESS;
2556 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2558 MSIPACKAGE* package = (MSIPACKAGE*)param;
2559 LPCWSTR cond = NULL;
2560 LPCWSTR message = NULL;
2561 UINT r;
2563 static const WCHAR title[]=
2564 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2566 cond = MSI_RecordGetString(row,1);
2568 r = MSI_EvaluateConditionW(package,cond);
2569 if (r == MSICONDITION_FALSE)
2571 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2573 LPWSTR deformated;
2574 message = MSI_RecordGetString(row,2);
2575 deformat_string(package,message,&deformated);
2576 MessageBoxW(NULL,deformated,title,MB_OK);
2577 msi_free(deformated);
2580 return ERROR_INSTALL_FAILURE;
2583 return ERROR_SUCCESS;
2586 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2588 UINT rc;
2589 MSIQUERY * view = NULL;
2590 static const WCHAR ExecSeqQuery[] =
2591 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2592 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2594 TRACE("Checking launch conditions\n");
2596 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2597 if (rc != ERROR_SUCCESS)
2598 return ERROR_SUCCESS;
2600 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2601 msiobj_release(&view->hdr);
2603 return rc;
2606 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2609 if (!cmp->KeyPath)
2610 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2612 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2614 MSIRECORD * row = 0;
2615 UINT root,len;
2616 LPWSTR deformated,buffer,deformated_name;
2617 LPCWSTR key,name;
2618 static const WCHAR ExecSeqQuery[] =
2619 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2620 '`','R','e','g','i','s','t','r','y','`',' ',
2621 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2622 ' ','=',' ' ,'\'','%','s','\'',0 };
2623 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2624 static const WCHAR fmt2[]=
2625 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2627 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2628 if (!row)
2629 return NULL;
2631 root = MSI_RecordGetInteger(row,2);
2632 key = MSI_RecordGetString(row, 3);
2633 name = MSI_RecordGetString(row, 4);
2634 deformat_string(package, key , &deformated);
2635 deformat_string(package, name, &deformated_name);
2637 len = strlenW(deformated) + 6;
2638 if (deformated_name)
2639 len+=strlenW(deformated_name);
2641 buffer = msi_alloc( len *sizeof(WCHAR));
2643 if (deformated_name)
2644 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2645 else
2646 sprintfW(buffer,fmt,root,deformated);
2648 msi_free(deformated);
2649 msi_free(deformated_name);
2650 msiobj_release(&row->hdr);
2652 return buffer;
2654 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2656 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2657 return NULL;
2659 else
2661 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2663 if (file)
2664 return strdupW( file->TargetPath );
2666 return NULL;
2669 static HKEY openSharedDLLsKey(void)
2671 HKEY hkey=0;
2672 static const WCHAR path[] =
2673 {'S','o','f','t','w','a','r','e','\\',
2674 'M','i','c','r','o','s','o','f','t','\\',
2675 'W','i','n','d','o','w','s','\\',
2676 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2677 'S','h','a','r','e','d','D','L','L','s',0};
2679 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2680 return hkey;
2683 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2685 HKEY hkey;
2686 DWORD count=0;
2687 DWORD type;
2688 DWORD sz = sizeof(count);
2689 DWORD rc;
2691 hkey = openSharedDLLsKey();
2692 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2693 if (rc != ERROR_SUCCESS)
2694 count = 0;
2695 RegCloseKey(hkey);
2696 return count;
2699 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2701 HKEY hkey;
2703 hkey = openSharedDLLsKey();
2704 if (count > 0)
2705 msi_reg_set_val_dword( hkey, path, count );
2706 else
2707 RegDeleteValueW(hkey,path);
2708 RegCloseKey(hkey);
2709 return count;
2713 * Return TRUE if the count should be written out and FALSE if not
2715 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2717 MSIFEATURE *feature;
2718 INT count = 0;
2719 BOOL write = FALSE;
2721 /* only refcount DLLs */
2722 if (comp->KeyPath == NULL ||
2723 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2724 comp->Attributes & msidbComponentAttributesODBCDataSource)
2725 write = FALSE;
2726 else
2728 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2729 write = (count > 0);
2731 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2732 write = TRUE;
2735 /* increment counts */
2736 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2738 ComponentList *cl;
2740 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2741 continue;
2743 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2745 if ( cl->component == comp )
2746 count++;
2750 /* decrement counts */
2751 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2753 ComponentList *cl;
2755 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2756 continue;
2758 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2760 if ( cl->component == comp )
2761 count--;
2765 /* ref count all the files in the component */
2766 if (write)
2768 MSIFILE *file;
2770 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2772 if (file->Component == comp)
2773 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2777 /* add a count for permanent */
2778 if (comp->Attributes & msidbComponentAttributesPermanent)
2779 count ++;
2781 comp->RefCount = count;
2783 if (write)
2784 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2788 * Ok further analysis makes me think that this work is
2789 * actually done in the PublishComponents and PublishFeatures
2790 * step, and not here. It appears like the keypath and all that is
2791 * resolved in this step, however actually written in the Publish steps.
2792 * But we will leave it here for now because it is unclear
2794 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2796 WCHAR squished_pc[GUID_SIZE];
2797 WCHAR squished_cc[GUID_SIZE];
2798 UINT rc;
2799 MSICOMPONENT *comp;
2800 HKEY hkey=0,hkey2=0;
2802 TRACE("\n");
2804 /* writes the Component and Features values to the registry */
2806 rc = MSIREG_OpenComponents(&hkey);
2807 if (rc != ERROR_SUCCESS)
2808 return rc;
2810 squash_guid(package->ProductCode,squished_pc);
2811 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2813 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2815 MSIRECORD * uirow;
2817 ui_progress(package,2,0,0,0);
2818 if (!comp->ComponentId)
2819 continue;
2821 squash_guid(comp->ComponentId,squished_cc);
2823 msi_free(comp->FullKeypath);
2824 comp->FullKeypath = resolve_keypath( package, comp );
2826 /* do the refcounting */
2827 ACTION_RefCountComponent( package, comp );
2829 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2830 debugstr_w(comp->Component),
2831 debugstr_w(squished_cc),
2832 debugstr_w(comp->FullKeypath),
2833 comp->RefCount);
2835 * Write the keypath out if the component is to be registered
2836 * and delete the key if the component is to be unregistered
2838 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2840 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2841 if (rc != ERROR_SUCCESS)
2842 continue;
2844 if (!comp->FullKeypath)
2845 continue;
2847 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2849 if (comp->Attributes & msidbComponentAttributesPermanent)
2851 static const WCHAR szPermKey[] =
2852 { '0','0','0','0','0','0','0','0','0','0','0','0',
2853 '0','0','0','0','0','0','0','0','0','0','0','0',
2854 '0','0','0','0','0','0','0','0',0 };
2856 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2859 RegCloseKey(hkey2);
2861 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, &hkey2, TRUE);
2862 if (rc != ERROR_SUCCESS)
2863 continue;
2865 msi_reg_set_val_str(hkey2, squished_pc, comp->FullKeypath);
2866 RegCloseKey(hkey2);
2868 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2870 DWORD res;
2872 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2873 if (rc != ERROR_SUCCESS)
2874 continue;
2876 RegDeleteValueW(hkey2,squished_pc);
2878 /* if the key is empty delete it */
2879 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2880 RegCloseKey(hkey2);
2881 if (res == ERROR_NO_MORE_ITEMS)
2882 RegDeleteKeyW(hkey,squished_cc);
2884 MSIREG_DeleteUserDataComponentKey(comp->ComponentId);
2887 /* UI stuff */
2888 uirow = MSI_CreateRecord(3);
2889 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2890 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2891 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2892 ui_actiondata(package,szProcessComponents,uirow);
2893 msiobj_release( &uirow->hdr );
2895 RegCloseKey(hkey);
2896 return rc;
2899 typedef struct {
2900 CLSID clsid;
2901 LPWSTR source;
2903 LPWSTR path;
2904 ITypeLib *ptLib;
2905 } typelib_struct;
2907 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
2908 LPWSTR lpszName, LONG_PTR lParam)
2910 TLIBATTR *attr;
2911 typelib_struct *tl_struct = (typelib_struct*) lParam;
2912 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2913 int sz;
2914 HRESULT res;
2916 if (!IS_INTRESOURCE(lpszName))
2918 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2919 return TRUE;
2922 sz = strlenW(tl_struct->source)+4;
2923 sz *= sizeof(WCHAR);
2925 if ((INT_PTR)lpszName == 1)
2926 tl_struct->path = strdupW(tl_struct->source);
2927 else
2929 tl_struct->path = msi_alloc(sz);
2930 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2933 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2934 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2935 if (!SUCCEEDED(res))
2937 msi_free(tl_struct->path);
2938 tl_struct->path = NULL;
2940 return TRUE;
2943 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2944 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2946 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2947 return FALSE;
2950 msi_free(tl_struct->path);
2951 tl_struct->path = NULL;
2953 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2954 ITypeLib_Release(tl_struct->ptLib);
2956 return TRUE;
2959 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2961 MSIPACKAGE* package = (MSIPACKAGE*)param;
2962 LPCWSTR component;
2963 MSICOMPONENT *comp;
2964 MSIFILE *file;
2965 typelib_struct tl_struct;
2966 HMODULE module;
2967 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2969 component = MSI_RecordGetString(row,3);
2970 comp = get_loaded_component(package,component);
2971 if (!comp)
2972 return ERROR_SUCCESS;
2974 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2976 TRACE("Skipping typelib reg due to disabled component\n");
2978 comp->Action = comp->Installed;
2980 return ERROR_SUCCESS;
2983 comp->Action = INSTALLSTATE_LOCAL;
2985 file = get_loaded_file( package, comp->KeyPath );
2986 if (!file)
2987 return ERROR_SUCCESS;
2989 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2990 if (module)
2992 LPCWSTR guid;
2993 guid = MSI_RecordGetString(row,1);
2994 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2995 tl_struct.source = strdupW( file->TargetPath );
2996 tl_struct.path = NULL;
2998 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2999 (LONG_PTR)&tl_struct);
3001 if (tl_struct.path)
3003 LPWSTR help = NULL;
3004 LPCWSTR helpid;
3005 HRESULT res;
3007 helpid = MSI_RecordGetString(row,6);
3009 if (helpid)
3010 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3011 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3012 msi_free(help);
3014 if (!SUCCEEDED(res))
3015 ERR("Failed to register type library %s\n",
3016 debugstr_w(tl_struct.path));
3017 else
3019 ui_actiondata(package,szRegisterTypeLibraries,row);
3021 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3024 ITypeLib_Release(tl_struct.ptLib);
3025 msi_free(tl_struct.path);
3027 else
3028 ERR("Failed to load type library %s\n",
3029 debugstr_w(tl_struct.source));
3031 FreeLibrary(module);
3032 msi_free(tl_struct.source);
3034 else
3035 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
3037 return ERROR_SUCCESS;
3040 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3043 * OK this is a bit confusing.. I am given a _Component key and I believe
3044 * that the file that is being registered as a type library is the "key file
3045 * of that component" which I interpret to mean "The file in the KeyPath of
3046 * that component".
3048 UINT rc;
3049 MSIQUERY * view;
3050 static const WCHAR Query[] =
3051 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3052 '`','T','y','p','e','L','i','b','`',0};
3054 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3055 if (rc != ERROR_SUCCESS)
3056 return ERROR_SUCCESS;
3058 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3059 msiobj_release(&view->hdr);
3060 return rc;
3063 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3065 MSIPACKAGE *package = (MSIPACKAGE*)param;
3066 LPWSTR target_file, target_folder, filename;
3067 LPCWSTR buffer, extension;
3068 MSICOMPONENT *comp;
3069 static const WCHAR szlnk[]={'.','l','n','k',0};
3070 IShellLinkW *sl = NULL;
3071 IPersistFile *pf = NULL;
3072 HRESULT res;
3074 buffer = MSI_RecordGetString(row,4);
3075 comp = get_loaded_component(package,buffer);
3076 if (!comp)
3077 return ERROR_SUCCESS;
3079 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3081 TRACE("Skipping shortcut creation due to disabled component\n");
3083 comp->Action = comp->Installed;
3085 return ERROR_SUCCESS;
3088 comp->Action = INSTALLSTATE_LOCAL;
3090 ui_actiondata(package,szCreateShortcuts,row);
3092 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3093 &IID_IShellLinkW, (LPVOID *) &sl );
3095 if (FAILED( res ))
3097 ERR("CLSID_ShellLink not available\n");
3098 goto err;
3101 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3102 if (FAILED( res ))
3104 ERR("QueryInterface(IID_IPersistFile) failed\n");
3105 goto err;
3108 buffer = MSI_RecordGetString(row,2);
3109 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3111 /* may be needed because of a bug somewhere else */
3112 create_full_pathW(target_folder);
3114 filename = msi_dup_record_field( row, 3 );
3115 reduce_to_longfilename(filename);
3117 extension = strchrW(filename,'.');
3118 if (!extension || strcmpiW(extension,szlnk))
3120 int len = strlenW(filename);
3121 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3122 memcpy(filename + len, szlnk, sizeof(szlnk));
3124 target_file = build_directory_name(2, target_folder, filename);
3125 msi_free(target_folder);
3126 msi_free(filename);
3128 buffer = MSI_RecordGetString(row,5);
3129 if (strchrW(buffer,'['))
3131 LPWSTR deformated;
3132 deformat_string(package,buffer,&deformated);
3133 IShellLinkW_SetPath(sl,deformated);
3134 msi_free(deformated);
3136 else
3138 FIXME("poorly handled shortcut format, advertised shortcut\n");
3139 IShellLinkW_SetPath(sl,comp->FullKeypath);
3142 if (!MSI_RecordIsNull(row,6))
3144 LPWSTR deformated;
3145 buffer = MSI_RecordGetString(row,6);
3146 deformat_string(package,buffer,&deformated);
3147 IShellLinkW_SetArguments(sl,deformated);
3148 msi_free(deformated);
3151 if (!MSI_RecordIsNull(row,7))
3153 buffer = MSI_RecordGetString(row,7);
3154 IShellLinkW_SetDescription(sl,buffer);
3157 if (!MSI_RecordIsNull(row,8))
3158 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3160 if (!MSI_RecordIsNull(row,9))
3162 LPWSTR Path;
3163 INT index;
3165 buffer = MSI_RecordGetString(row,9);
3167 Path = build_icon_path(package,buffer);
3168 index = MSI_RecordGetInteger(row,10);
3170 /* no value means 0 */
3171 if (index == MSI_NULL_INTEGER)
3172 index = 0;
3174 IShellLinkW_SetIconLocation(sl,Path,index);
3175 msi_free(Path);
3178 if (!MSI_RecordIsNull(row,11))
3179 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3181 if (!MSI_RecordIsNull(row,12))
3183 LPWSTR Path;
3184 buffer = MSI_RecordGetString(row,12);
3185 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3186 if (Path)
3187 IShellLinkW_SetWorkingDirectory(sl,Path);
3188 msi_free(Path);
3191 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3192 IPersistFile_Save(pf,target_file,FALSE);
3194 msi_free(target_file);
3196 err:
3197 if (pf)
3198 IPersistFile_Release( pf );
3199 if (sl)
3200 IShellLinkW_Release( sl );
3202 return ERROR_SUCCESS;
3205 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3207 UINT rc;
3208 HRESULT res;
3209 MSIQUERY * view;
3210 static const WCHAR Query[] =
3211 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3212 '`','S','h','o','r','t','c','u','t','`',0};
3214 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3215 if (rc != ERROR_SUCCESS)
3216 return ERROR_SUCCESS;
3218 res = CoInitialize( NULL );
3219 if (FAILED (res))
3221 ERR("CoInitialize failed\n");
3222 return ERROR_FUNCTION_FAILED;
3225 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3226 msiobj_release(&view->hdr);
3228 CoUninitialize();
3230 return rc;
3233 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3235 MSIPACKAGE* package = (MSIPACKAGE*)param;
3236 HANDLE the_file;
3237 LPWSTR FilePath;
3238 LPCWSTR FileName;
3239 CHAR buffer[1024];
3240 DWORD sz;
3241 UINT rc;
3242 MSIRECORD *uirow;
3244 FileName = MSI_RecordGetString(row,1);
3245 if (!FileName)
3247 ERR("Unable to get FileName\n");
3248 return ERROR_SUCCESS;
3251 FilePath = build_icon_path(package,FileName);
3253 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3255 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3256 FILE_ATTRIBUTE_NORMAL, NULL);
3258 if (the_file == INVALID_HANDLE_VALUE)
3260 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3261 msi_free(FilePath);
3262 return ERROR_SUCCESS;
3267 DWORD write;
3268 sz = 1024;
3269 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3270 if (rc != ERROR_SUCCESS)
3272 ERR("Failed to get stream\n");
3273 CloseHandle(the_file);
3274 DeleteFileW(FilePath);
3275 break;
3277 WriteFile(the_file,buffer,sz,&write,NULL);
3278 } while (sz == 1024);
3280 msi_free(FilePath);
3282 CloseHandle(the_file);
3284 uirow = MSI_CreateRecord(1);
3285 MSI_RecordSetStringW(uirow,1,FileName);
3286 ui_actiondata(package,szPublishProduct,uirow);
3287 msiobj_release( &uirow->hdr );
3289 return ERROR_SUCCESS;
3292 static BOOL msi_check_publish(MSIPACKAGE *package)
3294 MSIFEATURE *feature;
3296 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3298 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3299 return TRUE;
3302 return FALSE;
3306 * 99% of the work done here is only done for
3307 * advertised installs. However this is where the
3308 * Icon table is processed and written out
3309 * so that is what I am going to do here.
3311 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3313 UINT rc;
3314 LPWSTR packname;
3315 MSIQUERY * view;
3316 MSISOURCELISTINFO *info;
3317 MSIMEDIADISK *disk;
3318 static const WCHAR Query[]=
3319 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3320 '`','I','c','o','n','`',0};
3321 /* for registry stuff */
3322 HKEY hkey=0;
3323 HKEY hukey=0;
3324 HKEY hudkey=0, props=0;
3325 HKEY source;
3326 static const WCHAR szProductLanguage[] =
3327 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3328 static const WCHAR szARPProductIcon[] =
3329 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3330 static const WCHAR szProductVersion[] =
3331 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3332 static const WCHAR szSourceList[] =
3333 {'S','o','u','r','c','e','L','i','s','t',0};
3334 static const WCHAR szEmpty[] = {0};
3335 DWORD langid;
3336 LPWSTR buffer;
3337 DWORD size;
3338 MSIHANDLE hDb, hSumInfo;
3340 /* FIXME: also need to publish if the product is in advertise mode */
3341 if (!msi_check_publish(package))
3342 return ERROR_SUCCESS;
3344 /* write out icon files */
3346 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3347 if (rc == ERROR_SUCCESS)
3349 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3350 msiobj_release(&view->hdr);
3353 /* ok there is a lot more done here but i need to figure out what */
3355 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3357 rc = MSIREG_OpenLocalClassesProductKey(package->ProductCode, &hukey, TRUE);
3358 if (rc != ERROR_SUCCESS)
3359 goto end;
3361 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
3362 if (rc != ERROR_SUCCESS)
3363 goto end;
3365 else
3367 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3368 if (rc != ERROR_SUCCESS)
3369 goto end;
3371 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3372 if (rc != ERROR_SUCCESS)
3373 goto end;
3375 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
3376 if (rc != ERROR_SUCCESS)
3377 goto end;
3380 rc = RegCreateKeyW(hukey, szSourceList, &source);
3381 if (rc != ERROR_SUCCESS)
3382 goto end;
3384 RegCloseKey(source);
3386 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3387 if (rc != ERROR_SUCCESS)
3388 goto end;
3390 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3391 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3392 msi_free(buffer);
3394 langid = msi_get_property_int( package, szProductLanguage, 0 );
3395 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_LANGUAGEW, langid );
3397 packname = strrchrW( package->PackagePath, '\\' ) + 1;
3398 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGENAMEW, packname );
3400 /* FIXME */
3401 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0 );
3402 msi_reg_set_val_dword( props, INSTALLPROPERTY_INSTANCETYPEW, 0 );
3404 buffer = msi_dup_property( package, szARPProductIcon );
3405 if (buffer)
3407 LPWSTR path = build_icon_path(package,buffer);
3408 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3409 msi_free( path );
3411 msi_free(buffer);
3413 buffer = msi_dup_property( package, szProductVersion );
3414 if (buffer)
3416 DWORD verdword = msi_version_str_to_dword(buffer);
3417 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_VERSIONW, verdword );
3419 msi_free(buffer);
3421 buffer = strrchrW( package->PackagePath, '\\') + 1;
3422 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
3423 package->Context, MSICODE_PRODUCT,
3424 INSTALLPROPERTY_PACKAGENAMEW, buffer );
3425 if (rc != ERROR_SUCCESS)
3426 goto end;
3428 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
3429 package->Context, MSICODE_PRODUCT,
3430 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty );
3431 if (rc != ERROR_SUCCESS)
3432 goto end;
3434 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
3435 package->Context, MSICODE_PRODUCT,
3436 INSTALLPROPERTY_DISKPROMPTW, szEmpty );
3437 if (rc != ERROR_SUCCESS)
3438 goto end;
3440 /* FIXME: Need to write more keys to the user registry */
3442 hDb= alloc_msihandle( &package->db->hdr );
3443 if (!hDb) {
3444 rc = ERROR_NOT_ENOUGH_MEMORY;
3445 goto end;
3447 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
3448 MsiCloseHandle(hDb);
3449 if (rc == ERROR_SUCCESS)
3451 WCHAR guidbuffer[0x200];
3452 size = 0x200;
3453 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3454 guidbuffer, &size);
3455 if (rc == ERROR_SUCCESS)
3457 /* for now we only care about the first guid */
3458 LPWSTR ptr = strchrW(guidbuffer,';');
3459 if (ptr) *ptr = 0;
3460 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, guidbuffer );
3462 else
3464 ERR("Unable to query Revision_Number...\n");
3465 rc = ERROR_SUCCESS;
3467 MsiCloseHandle(hSumInfo);
3469 else
3471 ERR("Unable to open Summary Information\n");
3472 rc = ERROR_SUCCESS;
3475 /* publish the SourceList info */
3476 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3478 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3479 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3480 info->options, info->value);
3481 else
3482 MsiSourceListSetInfoW(package->ProductCode, NULL,
3483 info->context, info->options,
3484 info->property, info->value);
3487 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3489 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3490 disk->context, disk->options,
3491 disk->disk_id, disk->volume_label, disk->disk_prompt);
3494 end:
3495 RegCloseKey(hkey);
3496 RegCloseKey(hukey);
3497 RegCloseKey(hudkey);
3498 RegCloseKey(props);
3500 return rc;
3503 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3505 MSIPACKAGE *package = (MSIPACKAGE*)param;
3506 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3507 LPWSTR deformated_section, deformated_key, deformated_value;
3508 LPWSTR folder, fullname = NULL;
3509 MSIRECORD * uirow;
3510 INT action;
3511 MSICOMPONENT *comp;
3512 static const WCHAR szWindowsFolder[] =
3513 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3515 component = MSI_RecordGetString(row, 8);
3516 comp = get_loaded_component(package,component);
3518 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3520 TRACE("Skipping ini file due to disabled component %s\n",
3521 debugstr_w(component));
3523 comp->Action = comp->Installed;
3525 return ERROR_SUCCESS;
3528 comp->Action = INSTALLSTATE_LOCAL;
3530 identifier = MSI_RecordGetString(row,1);
3531 filename = MSI_RecordGetString(row,2);
3532 dirproperty = MSI_RecordGetString(row,3);
3533 section = MSI_RecordGetString(row,4);
3534 key = MSI_RecordGetString(row,5);
3535 value = MSI_RecordGetString(row,6);
3536 action = MSI_RecordGetInteger(row,7);
3538 deformat_string(package,section,&deformated_section);
3539 deformat_string(package,key,&deformated_key);
3540 deformat_string(package,value,&deformated_value);
3542 if (dirproperty)
3544 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3545 if (!folder)
3546 folder = msi_dup_property( package, dirproperty );
3548 else
3549 folder = msi_dup_property( package, szWindowsFolder );
3551 if (!folder)
3553 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3554 goto cleanup;
3557 fullname = build_directory_name(2, folder, filename);
3559 if (action == 0)
3561 TRACE("Adding value %s to section %s in %s\n",
3562 debugstr_w(deformated_key), debugstr_w(deformated_section),
3563 debugstr_w(fullname));
3564 WritePrivateProfileStringW(deformated_section, deformated_key,
3565 deformated_value, fullname);
3567 else if (action == 1)
3569 WCHAR returned[10];
3570 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3571 returned, 10, fullname);
3572 if (returned[0] == 0)
3574 TRACE("Adding value %s to section %s in %s\n",
3575 debugstr_w(deformated_key), debugstr_w(deformated_section),
3576 debugstr_w(fullname));
3578 WritePrivateProfileStringW(deformated_section, deformated_key,
3579 deformated_value, fullname);
3582 else if (action == 3)
3583 FIXME("Append to existing section not yet implemented\n");
3585 uirow = MSI_CreateRecord(4);
3586 MSI_RecordSetStringW(uirow,1,identifier);
3587 MSI_RecordSetStringW(uirow,2,deformated_section);
3588 MSI_RecordSetStringW(uirow,3,deformated_key);
3589 MSI_RecordSetStringW(uirow,4,deformated_value);
3590 ui_actiondata(package,szWriteIniValues,uirow);
3591 msiobj_release( &uirow->hdr );
3592 cleanup:
3593 msi_free(fullname);
3594 msi_free(folder);
3595 msi_free(deformated_key);
3596 msi_free(deformated_value);
3597 msi_free(deformated_section);
3598 return ERROR_SUCCESS;
3601 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3603 UINT rc;
3604 MSIQUERY * view;
3605 static const WCHAR ExecSeqQuery[] =
3606 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3607 '`','I','n','i','F','i','l','e','`',0};
3609 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3610 if (rc != ERROR_SUCCESS)
3612 TRACE("no IniFile table\n");
3613 return ERROR_SUCCESS;
3616 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3617 msiobj_release(&view->hdr);
3618 return rc;
3621 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3623 MSIPACKAGE *package = (MSIPACKAGE*)param;
3624 LPCWSTR filename;
3625 LPWSTR FullName;
3626 MSIFILE *file;
3627 DWORD len;
3628 static const WCHAR ExeStr[] =
3629 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3630 static const WCHAR close[] = {'\"',0};
3631 STARTUPINFOW si;
3632 PROCESS_INFORMATION info;
3633 BOOL brc;
3634 MSIRECORD *uirow;
3635 LPWSTR uipath, p;
3637 memset(&si,0,sizeof(STARTUPINFOW));
3639 filename = MSI_RecordGetString(row,1);
3640 file = get_loaded_file( package, filename );
3642 if (!file)
3644 ERR("Unable to find file id %s\n",debugstr_w(filename));
3645 return ERROR_SUCCESS;
3648 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3650 FullName = msi_alloc(len*sizeof(WCHAR));
3651 strcpyW(FullName,ExeStr);
3652 strcatW( FullName, file->TargetPath );
3653 strcatW(FullName,close);
3655 TRACE("Registering %s\n",debugstr_w(FullName));
3656 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3657 &si, &info);
3659 if (brc)
3660 msi_dialog_check_messages(info.hProcess);
3662 msi_free(FullName);
3664 /* the UI chunk */
3665 uirow = MSI_CreateRecord( 2 );
3666 uipath = strdupW( file->TargetPath );
3667 p = strrchrW(uipath,'\\');
3668 if (p)
3669 p[0]=0;
3670 MSI_RecordSetStringW( uirow, 1, &p[1] );
3671 MSI_RecordSetStringW( uirow, 2, uipath);
3672 ui_actiondata( package, szSelfRegModules, uirow);
3673 msiobj_release( &uirow->hdr );
3674 msi_free( uipath );
3675 /* FIXME: call ui_progress? */
3677 return ERROR_SUCCESS;
3680 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3682 UINT rc;
3683 MSIQUERY * view;
3684 static const WCHAR ExecSeqQuery[] =
3685 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3686 '`','S','e','l','f','R','e','g','`',0};
3688 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3689 if (rc != ERROR_SUCCESS)
3691 TRACE("no SelfReg table\n");
3692 return ERROR_SUCCESS;
3695 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3696 msiobj_release(&view->hdr);
3698 return ERROR_SUCCESS;
3701 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3703 MSIFEATURE *feature;
3704 UINT rc;
3705 HKEY hkey=0;
3706 HKEY hukey=0;
3707 HKEY userdata=0;
3709 if (!msi_check_publish(package))
3710 return ERROR_SUCCESS;
3712 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3713 if (rc != ERROR_SUCCESS)
3714 goto end;
3716 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3717 if (rc != ERROR_SUCCESS)
3718 goto end;
3720 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &userdata, TRUE);
3721 if (rc != ERROR_SUCCESS)
3722 goto end;
3724 /* here the guids are base 85 encoded */
3725 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3727 ComponentList *cl;
3728 LPWSTR data = NULL;
3729 GUID clsid;
3730 INT size;
3731 BOOL absent = FALSE;
3732 MSIRECORD *uirow;
3734 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3735 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3736 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3737 absent = TRUE;
3739 size = 1;
3740 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3742 size += 21;
3744 if (feature->Feature_Parent)
3745 size += strlenW( feature->Feature_Parent )+2;
3747 data = msi_alloc(size * sizeof(WCHAR));
3749 data[0] = 0;
3750 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3752 MSICOMPONENT* component = cl->component;
3753 WCHAR buf[21];
3755 buf[0] = 0;
3756 if (component->ComponentId)
3758 TRACE("From %s\n",debugstr_w(component->ComponentId));
3759 CLSIDFromString(component->ComponentId, &clsid);
3760 encode_base85_guid(&clsid,buf);
3761 TRACE("to %s\n",debugstr_w(buf));
3762 strcatW(data,buf);
3766 if (feature->Feature_Parent)
3768 static const WCHAR sep[] = {'\2',0};
3769 strcatW(data,sep);
3770 strcatW(data,feature->Feature_Parent);
3773 msi_reg_set_val_str( hkey, feature->Feature, data );
3774 msi_reg_set_val_str( userdata, feature->Feature, data );
3775 msi_free(data);
3777 size = 0;
3778 if (feature->Feature_Parent)
3779 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3780 if (!absent)
3782 static const WCHAR emptyW[] = {0};
3783 size += sizeof(WCHAR);
3784 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3785 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
3787 else
3789 size += 2*sizeof(WCHAR);
3790 data = msi_alloc(size);
3791 data[0] = 0x6;
3792 data[1] = 0;
3793 if (feature->Feature_Parent)
3794 strcpyW( &data[1], feature->Feature_Parent );
3795 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3796 (LPBYTE)data,size);
3797 msi_free(data);
3800 /* the UI chunk */
3801 uirow = MSI_CreateRecord( 1 );
3802 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3803 ui_actiondata( package, szPublishFeatures, uirow);
3804 msiobj_release( &uirow->hdr );
3805 /* FIXME: call ui_progress? */
3808 end:
3809 RegCloseKey(hkey);
3810 RegCloseKey(hukey);
3811 return rc;
3814 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3816 UINT r;
3817 HKEY hkey;
3819 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3821 r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
3822 if (r == ERROR_SUCCESS)
3824 RegDeleteValueW(hkey, feature->Feature);
3825 RegCloseKey(hkey);
3828 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
3829 if (r == ERROR_SUCCESS)
3831 RegDeleteValueW(hkey, feature->Feature);
3832 RegCloseKey(hkey);
3835 return ERROR_SUCCESS;
3838 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3840 MSIFEATURE *feature;
3842 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3844 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3845 return FALSE;
3848 return TRUE;
3851 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3853 MSIFEATURE *feature;
3855 if (!msi_check_unpublish(package))
3856 return ERROR_SUCCESS;
3858 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3860 msi_unpublish_feature(package, feature);
3863 return ERROR_SUCCESS;
3866 static UINT msi_get_local_package_name( LPWSTR path )
3868 static const WCHAR szInstaller[] = {
3869 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3870 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3871 DWORD time, len, i;
3872 HANDLE handle;
3874 time = GetTickCount();
3875 GetWindowsDirectoryW( path, MAX_PATH );
3876 lstrcatW( path, szInstaller );
3877 CreateDirectoryW( path, NULL );
3879 len = lstrlenW(path);
3880 for (i=0; i<0x10000; i++)
3882 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3883 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3884 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3885 if (handle != INVALID_HANDLE_VALUE)
3887 CloseHandle(handle);
3888 break;
3890 if (GetLastError() != ERROR_FILE_EXISTS &&
3891 GetLastError() != ERROR_SHARING_VIOLATION)
3892 return ERROR_FUNCTION_FAILED;
3895 return ERROR_SUCCESS;
3898 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3900 WCHAR packagefile[MAX_PATH];
3901 HKEY props;
3902 UINT r;
3904 r = msi_get_local_package_name( packagefile );
3905 if (r != ERROR_SUCCESS)
3906 return r;
3908 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3910 r = CopyFileW( package->db->path, packagefile, FALSE);
3912 if (!r)
3914 ERR("Unable to copy package (%s -> %s) (error %d)\n",
3915 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
3916 return ERROR_FUNCTION_FAILED;
3919 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3921 r = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
3922 if (r != ERROR_SUCCESS)
3923 return r;
3925 msi_reg_set_val_str(props, INSTALLPROPERTY_LOCALPACKAGEW, packagefile);
3926 RegCloseKey(props);
3927 return ERROR_SUCCESS;
3930 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3932 LPWSTR prop, val, key;
3933 static const LPCSTR propval[] = {
3934 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3935 "ARPCONTACT", "Contact",
3936 "ARPCOMMENTS", "Comments",
3937 "ProductName", "DisplayName",
3938 "ProductVersion", "DisplayVersion",
3939 "ARPHELPLINK", "HelpLink",
3940 "ARPHELPTELEPHONE", "HelpTelephone",
3941 "ARPINSTALLLOCATION", "InstallLocation",
3942 "SourceDir", "InstallSource",
3943 "Manufacturer", "Publisher",
3944 "ARPREADME", "Readme",
3945 "ARPSIZE", "Size",
3946 "ARPURLINFOABOUT", "URLInfoAbout",
3947 "ARPURLUPDATEINFO", "URLUpdateInfo",
3948 NULL,
3950 const LPCSTR *p = propval;
3952 while( *p )
3954 prop = strdupAtoW( *p++ );
3955 key = strdupAtoW( *p++ );
3956 val = msi_dup_property( package, prop );
3957 msi_reg_set_val_str( hkey, key, val );
3958 msi_free(val);
3959 msi_free(key);
3960 msi_free(prop);
3962 return ERROR_SUCCESS;
3965 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3967 HKEY hkey=0;
3968 HKEY hudkey=0, props=0;
3969 LPWSTR buffer = NULL;
3970 UINT rc;
3971 DWORD size, langid;
3972 static const WCHAR szWindowsInstaller[] =
3973 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3974 static const WCHAR szUpgradeCode[] =
3975 {'U','p','g','r','a','d','e','C','o','d','e',0};
3976 static const WCHAR modpath_fmt[] =
3977 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3978 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3979 static const WCHAR szModifyPath[] =
3980 {'M','o','d','i','f','y','P','a','t','h',0};
3981 static const WCHAR szUninstallString[] =
3982 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3983 static const WCHAR szEstimatedSize[] =
3984 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3985 static const WCHAR szProductLanguage[] =
3986 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3987 static const WCHAR szProductVersion[] =
3988 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3989 static const WCHAR szProductName[] =
3990 {'P','r','o','d','u','c','t','N','a','m','e',0};
3991 static const WCHAR szDisplayName[] =
3992 {'D','i','s','p','l','a','y','N','a','m','e',0};
3993 static const WCHAR szDisplayVersion[] =
3994 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3995 static const WCHAR szManufacturer[] =
3996 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3998 SYSTEMTIME systime;
3999 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4000 LPWSTR upgrade_code;
4001 WCHAR szDate[9];
4003 /* FIXME: also need to publish if the product is in advertise mode */
4004 if (!msi_check_publish(package))
4005 return ERROR_SUCCESS;
4007 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
4008 if (rc != ERROR_SUCCESS)
4009 return rc;
4011 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4013 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
4014 if (rc != ERROR_SUCCESS)
4015 return rc;
4017 else
4019 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
4020 if (rc != ERROR_SUCCESS)
4021 return rc;
4024 /* dump all the info i can grab */
4025 /* FIXME: Flesh out more information */
4027 msi_write_uninstall_property_vals( package, hkey );
4029 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
4031 msi_make_package_local( package, hkey );
4033 /* do ModifyPath and UninstallString */
4034 size = deformat_string(package,modpath_fmt,&buffer);
4035 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
4036 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
4037 msi_free(buffer);
4039 /* FIXME: Write real Estimated Size when we have it */
4040 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
4042 buffer = msi_dup_property( package, szProductName );
4043 msi_reg_set_val_str( props, szDisplayName, buffer );
4044 msi_free(buffer);
4046 buffer = msi_dup_property( package, cszSourceDir );
4047 msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4048 msi_free(buffer);
4050 buffer = msi_dup_property( package, szManufacturer );
4051 msi_reg_set_val_str( props, INSTALLPROPERTY_PUBLISHERW, buffer);
4052 msi_free(buffer);
4054 GetLocalTime(&systime);
4055 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
4056 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
4057 msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLDATEW, szDate );
4059 langid = msi_get_property_int( package, szProductLanguage, 0 );
4060 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
4062 buffer = msi_dup_property( package, szProductVersion );
4063 msi_reg_set_val_str( props, szDisplayVersion, buffer );
4064 if (buffer)
4066 DWORD verdword = msi_version_str_to_dword(buffer);
4068 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
4069 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONW, verdword );
4070 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
4071 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
4072 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
4073 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
4075 msi_free(buffer);
4077 /* Handle Upgrade Codes */
4078 upgrade_code = msi_dup_property( package, szUpgradeCode );
4079 if (upgrade_code)
4081 HKEY hkey2;
4082 WCHAR squashed[33];
4083 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
4084 squash_guid(package->ProductCode,squashed);
4085 msi_reg_set_val_str( hkey2, squashed, NULL );
4086 RegCloseKey(hkey2);
4087 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
4088 squash_guid(package->ProductCode,squashed);
4089 msi_reg_set_val_str( hkey2, squashed, NULL );
4090 RegCloseKey(hkey2);
4092 msi_free(upgrade_code);
4095 RegCloseKey(hkey);
4097 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
4098 if (rc != ERROR_SUCCESS)
4099 return rc;
4101 RegCloseKey(hudkey);
4103 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
4104 RegCloseKey(props);
4106 return ERROR_SUCCESS;
4109 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4111 return execute_script(package,INSTALL_SCRIPT);
4114 static UINT msi_unpublish_product(MSIPACKAGE *package)
4116 LPWSTR remove = NULL;
4117 LPWSTR *features = NULL;
4118 BOOL full_uninstall = TRUE;
4119 MSIFEATURE *feature;
4121 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4122 static const WCHAR szAll[] = {'A','L','L',0};
4124 remove = msi_dup_property(package, szRemove);
4125 if (!remove)
4126 return ERROR_SUCCESS;
4128 features = msi_split_string(remove, ',');
4129 if (!features)
4131 msi_free(remove);
4132 ERR("REMOVE feature list is empty!\n");
4133 return ERROR_FUNCTION_FAILED;
4136 if (!lstrcmpW(features[0], szAll))
4137 full_uninstall = TRUE;
4138 else
4140 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4142 if (feature->Action != INSTALLSTATE_ABSENT)
4143 full_uninstall = FALSE;
4147 if (!full_uninstall)
4148 goto done;
4150 MSIREG_DeleteProductKey(package->ProductCode);
4151 MSIREG_DeleteUserProductKey(package->ProductCode);
4152 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4153 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4154 MSIREG_DeleteUninstallKey(package->ProductCode);
4156 done:
4157 msi_free(remove);
4158 msi_free(features);
4159 return ERROR_SUCCESS;
4162 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4164 UINT rc;
4166 rc = msi_unpublish_product(package);
4167 if (rc != ERROR_SUCCESS)
4168 return rc;
4170 /* turn off scheduling */
4171 package->script->CurrentlyScripting= FALSE;
4173 /* first do the same as an InstallExecute */
4174 rc = ACTION_InstallExecute(package);
4175 if (rc != ERROR_SUCCESS)
4176 return rc;
4178 /* then handle Commit Actions */
4179 rc = execute_script(package,COMMIT_SCRIPT);
4181 return rc;
4184 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4186 static const WCHAR RunOnce[] = {
4187 'S','o','f','t','w','a','r','e','\\',
4188 'M','i','c','r','o','s','o','f','t','\\',
4189 'W','i','n','d','o','w','s','\\',
4190 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4191 'R','u','n','O','n','c','e',0};
4192 static const WCHAR InstallRunOnce[] = {
4193 'S','o','f','t','w','a','r','e','\\',
4194 'M','i','c','r','o','s','o','f','t','\\',
4195 'W','i','n','d','o','w','s','\\',
4196 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4197 'I','n','s','t','a','l','l','e','r','\\',
4198 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4200 static const WCHAR msiexec_fmt[] = {
4201 '%','s',
4202 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4203 '\"','%','s','\"',0};
4204 static const WCHAR install_fmt[] = {
4205 '/','I',' ','\"','%','s','\"',' ',
4206 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4207 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4208 WCHAR buffer[256], sysdir[MAX_PATH];
4209 HKEY hkey;
4210 WCHAR squished_pc[100];
4212 squash_guid(package->ProductCode,squished_pc);
4214 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4215 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4216 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4217 squished_pc);
4219 msi_reg_set_val_str( hkey, squished_pc, buffer );
4220 RegCloseKey(hkey);
4222 TRACE("Reboot command %s\n",debugstr_w(buffer));
4224 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4225 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4227 msi_reg_set_val_str( hkey, squished_pc, buffer );
4228 RegCloseKey(hkey);
4230 return ERROR_INSTALL_SUSPEND;
4233 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4235 DWORD attrib;
4236 UINT rc;
4239 * We are currently doing what should be done here in the top level Install
4240 * however for Administrative and uninstalls this step will be needed
4242 if (!package->PackagePath)
4243 return ERROR_SUCCESS;
4245 msi_set_sourcedir_props(package, TRUE);
4247 attrib = GetFileAttributesW(package->db->path);
4248 if (attrib == INVALID_FILE_ATTRIBUTES)
4250 LPWSTR prompt;
4251 LPWSTR msg;
4252 DWORD size = 0;
4254 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4255 package->Context, MSICODE_PRODUCT,
4256 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4257 if (rc == ERROR_MORE_DATA)
4259 prompt = msi_alloc(size * sizeof(WCHAR));
4260 MsiSourceListGetInfoW(package->ProductCode, NULL,
4261 package->Context, MSICODE_PRODUCT,
4262 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4264 else
4265 prompt = strdupW(package->db->path);
4267 msg = generate_error_string(package,1302,1,prompt);
4268 while(attrib == INVALID_FILE_ATTRIBUTES)
4270 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4271 if (rc == IDCANCEL)
4273 rc = ERROR_INSTALL_USEREXIT;
4274 break;
4276 attrib = GetFileAttributesW(package->db->path);
4278 msi_free(prompt);
4279 rc = ERROR_SUCCESS;
4281 else
4282 return ERROR_SUCCESS;
4284 return rc;
4287 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4289 HKEY hkey=0;
4290 LPWSTR buffer;
4291 LPWSTR productid;
4292 UINT rc,i;
4294 static const WCHAR szPropKeys[][80] =
4296 {'P','r','o','d','u','c','t','I','D',0},
4297 {'U','S','E','R','N','A','M','E',0},
4298 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4299 {0},
4302 static const WCHAR szRegKeys[][80] =
4304 {'P','r','o','d','u','c','t','I','D',0},
4305 {'R','e','g','O','w','n','e','r',0},
4306 {'R','e','g','C','o','m','p','a','n','y',0},
4307 {0},
4310 if (msi_check_unpublish(package))
4312 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4313 return ERROR_SUCCESS;
4316 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4317 if (!productid)
4318 return ERROR_SUCCESS;
4320 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &hkey, TRUE);
4321 if (rc != ERROR_SUCCESS)
4322 goto end;
4324 for( i = 0; szPropKeys[i][0]; i++ )
4326 buffer = msi_dup_property( package, szPropKeys[i] );
4327 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4328 msi_free( buffer );
4331 end:
4332 msi_free(productid);
4333 RegCloseKey(hkey);
4335 /* FIXME: call ui_actiondata */
4337 return rc;
4341 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4343 UINT rc;
4345 package->script->InWhatSequence |= SEQUENCE_EXEC;
4346 rc = ACTION_ProcessExecSequence(package,FALSE);
4347 return rc;
4351 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4353 MSIPACKAGE *package = (MSIPACKAGE*)param;
4354 LPCWSTR compgroupid=NULL;
4355 LPCWSTR feature=NULL;
4356 LPCWSTR text = NULL;
4357 LPCWSTR qualifier = NULL;
4358 LPCWSTR component = NULL;
4359 LPWSTR advertise = NULL;
4360 LPWSTR output = NULL;
4361 HKEY hkey;
4362 UINT rc = ERROR_SUCCESS;
4363 MSICOMPONENT *comp;
4364 DWORD sz = 0;
4365 MSIRECORD *uirow;
4367 component = MSI_RecordGetString(rec,3);
4368 comp = get_loaded_component(package,component);
4370 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4371 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4372 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4374 TRACE("Skipping: Component %s not scheduled for install\n",
4375 debugstr_w(component));
4377 return ERROR_SUCCESS;
4380 compgroupid = MSI_RecordGetString(rec,1);
4381 qualifier = MSI_RecordGetString(rec,2);
4383 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4384 if (rc != ERROR_SUCCESS)
4385 goto end;
4387 text = MSI_RecordGetString(rec,4);
4388 feature = MSI_RecordGetString(rec,5);
4390 advertise = create_component_advertise_string(package, comp, feature);
4392 sz = strlenW(advertise);
4394 if (text)
4395 sz += lstrlenW(text);
4397 sz+=3;
4398 sz *= sizeof(WCHAR);
4400 output = msi_alloc_zero(sz);
4401 strcpyW(output,advertise);
4402 msi_free(advertise);
4404 if (text)
4405 strcatW(output,text);
4407 msi_reg_set_val_multi_str( hkey, qualifier, output );
4409 end:
4410 RegCloseKey(hkey);
4411 msi_free(output);
4413 /* the UI chunk */
4414 uirow = MSI_CreateRecord( 2 );
4415 MSI_RecordSetStringW( uirow, 1, compgroupid );
4416 MSI_RecordSetStringW( uirow, 2, qualifier);
4417 ui_actiondata( package, szPublishComponents, uirow);
4418 msiobj_release( &uirow->hdr );
4419 /* FIXME: call ui_progress? */
4421 return rc;
4425 * At present I am ignorning the advertised components part of this and only
4426 * focusing on the qualified component sets
4428 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4430 UINT rc;
4431 MSIQUERY * view;
4432 static const WCHAR ExecSeqQuery[] =
4433 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4434 '`','P','u','b','l','i','s','h',
4435 'C','o','m','p','o','n','e','n','t','`',0};
4437 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4438 if (rc != ERROR_SUCCESS)
4439 return ERROR_SUCCESS;
4441 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4442 msiobj_release(&view->hdr);
4444 return rc;
4447 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4449 MSIPACKAGE *package = (MSIPACKAGE*)param;
4450 MSIRECORD *row;
4451 MSIFILE *file;
4452 SC_HANDLE hscm, service = NULL;
4453 LPCWSTR comp, depends, pass;
4454 LPWSTR name = NULL, disp = NULL;
4455 LPCWSTR load_order, serv_name, key;
4456 DWORD serv_type, start_type;
4457 DWORD err_control;
4459 static const WCHAR query[] =
4460 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4461 '`','C','o','m','p','o','n','e','n','t','`',' ',
4462 'W','H','E','R','E',' ',
4463 '`','C','o','m','p','o','n','e','n','t','`',' ',
4464 '=','\'','%','s','\'',0};
4466 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4467 if (!hscm)
4469 ERR("Failed to open the SC Manager!\n");
4470 goto done;
4473 start_type = MSI_RecordGetInteger(rec, 5);
4474 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4475 goto done;
4477 depends = MSI_RecordGetString(rec, 8);
4478 if (depends && *depends)
4479 FIXME("Dependency list unhandled!\n");
4481 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4482 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4483 serv_type = MSI_RecordGetInteger(rec, 4);
4484 err_control = MSI_RecordGetInteger(rec, 6);
4485 load_order = MSI_RecordGetString(rec, 7);
4486 serv_name = MSI_RecordGetString(rec, 9);
4487 pass = MSI_RecordGetString(rec, 10);
4488 comp = MSI_RecordGetString(rec, 12);
4490 /* fetch the service path */
4491 row = MSI_QueryGetRecord(package->db, query, comp);
4492 if (!row)
4494 ERR("Control query failed!\n");
4495 goto done;
4498 key = MSI_RecordGetString(row, 6);
4500 file = get_loaded_file(package, key);
4501 msiobj_release(&row->hdr);
4502 if (!file)
4504 ERR("Failed to load the service file\n");
4505 goto done;
4508 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4509 start_type, err_control, file->TargetPath,
4510 load_order, NULL, NULL, serv_name, pass);
4511 if (!service)
4513 if (GetLastError() != ERROR_SERVICE_EXISTS)
4514 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4517 done:
4518 CloseServiceHandle(service);
4519 CloseServiceHandle(hscm);
4520 msi_free(name);
4521 msi_free(disp);
4523 return ERROR_SUCCESS;
4526 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4528 UINT rc;
4529 MSIQUERY * view;
4530 static const WCHAR ExecSeqQuery[] =
4531 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4532 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4534 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4535 if (rc != ERROR_SUCCESS)
4536 return ERROR_SUCCESS;
4538 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4539 msiobj_release(&view->hdr);
4541 return rc;
4544 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4545 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4547 LPCWSTR *vector, *temp_vector;
4548 LPWSTR p, q;
4549 DWORD sep_len;
4551 static const WCHAR separator[] = {'[','~',']',0};
4553 *numargs = 0;
4554 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4556 if (!args)
4557 return NULL;
4559 vector = msi_alloc(sizeof(LPWSTR));
4560 if (!vector)
4561 return NULL;
4563 p = args;
4566 (*numargs)++;
4567 vector[*numargs - 1] = p;
4569 if ((q = strstrW(p, separator)))
4571 *q = '\0';
4573 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4574 if (!temp_vector)
4576 msi_free(vector);
4577 return NULL;
4579 vector = temp_vector;
4581 p = q + sep_len;
4583 } while (q);
4585 return vector;
4588 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4590 MSIPACKAGE *package = (MSIPACKAGE *)param;
4591 MSICOMPONENT *comp;
4592 SC_HANDLE scm, service = NULL;
4593 LPCWSTR name, *vector = NULL;
4594 LPWSTR args;
4595 DWORD event, numargs;
4596 UINT r = ERROR_FUNCTION_FAILED;
4598 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4599 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4600 return ERROR_SUCCESS;
4602 name = MSI_RecordGetString(rec, 2);
4603 event = MSI_RecordGetInteger(rec, 3);
4604 args = strdupW(MSI_RecordGetString(rec, 4));
4606 if (!(event & msidbServiceControlEventStart))
4607 return ERROR_SUCCESS;
4609 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4610 if (!scm)
4612 ERR("Failed to open the service control manager\n");
4613 goto done;
4616 service = OpenServiceW(scm, name, SERVICE_START);
4617 if (!service)
4619 ERR("Failed to open service %s\n", debugstr_w(name));
4620 goto done;
4623 vector = msi_service_args_to_vector(args, &numargs);
4625 if (!StartServiceW(service, numargs, vector))
4627 ERR("Failed to start service %s\n", debugstr_w(name));
4628 goto done;
4631 r = ERROR_SUCCESS;
4633 done:
4634 CloseServiceHandle(service);
4635 CloseServiceHandle(scm);
4637 msi_free(args);
4638 msi_free(vector);
4639 return r;
4642 static UINT ACTION_StartServices( MSIPACKAGE *package )
4644 UINT rc;
4645 MSIQUERY *view;
4647 static const WCHAR query[] = {
4648 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4649 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4651 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4652 if (rc != ERROR_SUCCESS)
4653 return ERROR_SUCCESS;
4655 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4656 msiobj_release(&view->hdr);
4658 return rc;
4661 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4663 DWORD i, needed, count;
4664 ENUM_SERVICE_STATUSW *dependencies;
4665 SERVICE_STATUS ss;
4666 SC_HANDLE depserv;
4668 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4669 0, &needed, &count))
4670 return TRUE;
4672 if (GetLastError() != ERROR_MORE_DATA)
4673 return FALSE;
4675 dependencies = msi_alloc(needed);
4676 if (!dependencies)
4677 return FALSE;
4679 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4680 needed, &needed, &count))
4681 goto error;
4683 for (i = 0; i < count; i++)
4685 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4686 SERVICE_STOP | SERVICE_QUERY_STATUS);
4687 if (!depserv)
4688 goto error;
4690 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4691 goto error;
4694 return TRUE;
4696 error:
4697 msi_free(dependencies);
4698 return FALSE;
4701 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4703 MSIPACKAGE *package = (MSIPACKAGE *)param;
4704 MSICOMPONENT *comp;
4705 SERVICE_STATUS status;
4706 SERVICE_STATUS_PROCESS ssp;
4707 SC_HANDLE scm = NULL, service = NULL;
4708 LPWSTR name, args;
4709 DWORD event, needed;
4711 event = MSI_RecordGetInteger(rec, 3);
4712 if (!(event & msidbServiceControlEventStop))
4713 return ERROR_SUCCESS;
4715 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4716 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4717 return ERROR_SUCCESS;
4719 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4720 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4721 args = strdupW(MSI_RecordGetString(rec, 4));
4723 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4724 if (!scm)
4726 WARN("Failed to open the SCM: %d\n", GetLastError());
4727 goto done;
4730 service = OpenServiceW(scm, name,
4731 SERVICE_STOP |
4732 SERVICE_QUERY_STATUS |
4733 SERVICE_ENUMERATE_DEPENDENTS);
4734 if (!service)
4736 WARN("Failed to open service (%s): %d\n",
4737 debugstr_w(name), GetLastError());
4738 goto done;
4741 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4742 sizeof(SERVICE_STATUS_PROCESS), &needed))
4744 WARN("Failed to query service status (%s): %d\n",
4745 debugstr_w(name), GetLastError());
4746 goto done;
4749 if (ssp.dwCurrentState == SERVICE_STOPPED)
4750 goto done;
4752 stop_service_dependents(scm, service);
4754 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4755 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4757 done:
4758 CloseServiceHandle(service);
4759 CloseServiceHandle(scm);
4760 msi_free(name);
4761 msi_free(args);
4763 return ERROR_SUCCESS;
4766 static UINT ACTION_StopServices( MSIPACKAGE *package )
4768 UINT rc;
4769 MSIQUERY *view;
4771 static const WCHAR query[] = {
4772 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4773 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4775 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4776 if (rc != ERROR_SUCCESS)
4777 return ERROR_SUCCESS;
4779 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4780 msiobj_release(&view->hdr);
4782 return rc;
4785 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4787 MSIFILE *file;
4789 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4791 if (!lstrcmpW(file->File, filename))
4792 return file;
4795 return NULL;
4798 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4800 MSIPACKAGE *package = (MSIPACKAGE*)param;
4801 LPWSTR driver, driver_path, ptr;
4802 WCHAR outpath[MAX_PATH];
4803 MSIFILE *driver_file, *setup_file;
4804 LPCWSTR desc;
4805 DWORD len, usage;
4806 UINT r = ERROR_SUCCESS;
4808 static const WCHAR driver_fmt[] = {
4809 'D','r','i','v','e','r','=','%','s',0};
4810 static const WCHAR setup_fmt[] = {
4811 'S','e','t','u','p','=','%','s',0};
4812 static const WCHAR usage_fmt[] = {
4813 'F','i','l','e','U','s','a','g','e','=','1',0};
4815 desc = MSI_RecordGetString(rec, 3);
4817 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4818 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4820 if (!driver_file || !setup_file)
4822 ERR("ODBC Driver entry not found!\n");
4823 return ERROR_FUNCTION_FAILED;
4826 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4827 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4828 lstrlenW(usage_fmt) + 1;
4829 driver = msi_alloc(len * sizeof(WCHAR));
4830 if (!driver)
4831 return ERROR_OUTOFMEMORY;
4833 ptr = driver;
4834 lstrcpyW(ptr, desc);
4835 ptr += lstrlenW(ptr) + 1;
4837 sprintfW(ptr, driver_fmt, driver_file->FileName);
4838 ptr += lstrlenW(ptr) + 1;
4840 sprintfW(ptr, setup_fmt, setup_file->FileName);
4841 ptr += lstrlenW(ptr) + 1;
4843 lstrcpyW(ptr, usage_fmt);
4844 ptr += lstrlenW(ptr) + 1;
4845 *ptr = '\0';
4847 driver_path = strdupW(driver_file->TargetPath);
4848 ptr = strrchrW(driver_path, '\\');
4849 if (ptr) *ptr = '\0';
4851 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4852 NULL, ODBC_INSTALL_COMPLETE, &usage))
4854 ERR("Failed to install SQL driver!\n");
4855 r = ERROR_FUNCTION_FAILED;
4858 msi_free(driver);
4859 msi_free(driver_path);
4861 return r;
4864 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4866 MSIPACKAGE *package = (MSIPACKAGE*)param;
4867 LPWSTR translator, translator_path, ptr;
4868 WCHAR outpath[MAX_PATH];
4869 MSIFILE *translator_file, *setup_file;
4870 LPCWSTR desc;
4871 DWORD len, usage;
4872 UINT r = ERROR_SUCCESS;
4874 static const WCHAR translator_fmt[] = {
4875 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4876 static const WCHAR setup_fmt[] = {
4877 'S','e','t','u','p','=','%','s',0};
4879 desc = MSI_RecordGetString(rec, 3);
4881 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4882 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4884 if (!translator_file || !setup_file)
4886 ERR("ODBC Translator entry not found!\n");
4887 return ERROR_FUNCTION_FAILED;
4890 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4891 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4892 translator = msi_alloc(len * sizeof(WCHAR));
4893 if (!translator)
4894 return ERROR_OUTOFMEMORY;
4896 ptr = translator;
4897 lstrcpyW(ptr, desc);
4898 ptr += lstrlenW(ptr) + 1;
4900 sprintfW(ptr, translator_fmt, translator_file->FileName);
4901 ptr += lstrlenW(ptr) + 1;
4903 sprintfW(ptr, setup_fmt, setup_file->FileName);
4904 ptr += lstrlenW(ptr) + 1;
4905 *ptr = '\0';
4907 translator_path = strdupW(translator_file->TargetPath);
4908 ptr = strrchrW(translator_path, '\\');
4909 if (ptr) *ptr = '\0';
4911 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4912 NULL, ODBC_INSTALL_COMPLETE, &usage))
4914 ERR("Failed to install SQL translator!\n");
4915 r = ERROR_FUNCTION_FAILED;
4918 msi_free(translator);
4919 msi_free(translator_path);
4921 return r;
4924 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4926 LPWSTR attrs;
4927 LPCWSTR desc, driver;
4928 WORD request = ODBC_ADD_SYS_DSN;
4929 INT registration;
4930 DWORD len;
4931 UINT r = ERROR_SUCCESS;
4933 static const WCHAR attrs_fmt[] = {
4934 'D','S','N','=','%','s',0 };
4936 desc = MSI_RecordGetString(rec, 3);
4937 driver = MSI_RecordGetString(rec, 4);
4938 registration = MSI_RecordGetInteger(rec, 5);
4940 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4941 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4943 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4944 attrs = msi_alloc(len * sizeof(WCHAR));
4945 if (!attrs)
4946 return ERROR_OUTOFMEMORY;
4948 sprintfW(attrs, attrs_fmt, desc);
4949 attrs[len - 1] = '\0';
4951 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4953 ERR("Failed to install SQL data source!\n");
4954 r = ERROR_FUNCTION_FAILED;
4957 msi_free(attrs);
4959 return r;
4962 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4964 UINT rc;
4965 MSIQUERY *view;
4967 static const WCHAR driver_query[] = {
4968 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4969 'O','D','B','C','D','r','i','v','e','r',0 };
4971 static const WCHAR translator_query[] = {
4972 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4973 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4975 static const WCHAR source_query[] = {
4976 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4977 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4979 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
4980 if (rc != ERROR_SUCCESS)
4981 return ERROR_SUCCESS;
4983 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4984 msiobj_release(&view->hdr);
4986 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4987 if (rc != ERROR_SUCCESS)
4988 return ERROR_SUCCESS;
4990 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4991 msiobj_release(&view->hdr);
4993 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4994 if (rc != ERROR_SUCCESS)
4995 return ERROR_SUCCESS;
4997 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4998 msiobj_release(&view->hdr);
5000 return rc;
5003 #define ENV_ACT_SETALWAYS 0x1
5004 #define ENV_ACT_SETABSENT 0x2
5005 #define ENV_ACT_REMOVE 0x4
5006 #define ENV_ACT_REMOVEMATCH 0x8
5008 #define ENV_MOD_MACHINE 0x20000000
5009 #define ENV_MOD_APPEND 0x40000000
5010 #define ENV_MOD_PREFIX 0x80000000
5011 #define ENV_MOD_MASK 0xC0000000
5013 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5015 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5017 LPCWSTR cptr = *name;
5018 LPCWSTR ptr = *value;
5020 static const WCHAR prefix[] = {'[','~',']',0};
5021 static const int prefix_len = 3;
5023 *flags = 0;
5024 while (*cptr)
5026 if (*cptr == '=')
5027 *flags |= ENV_ACT_SETALWAYS;
5028 else if (*cptr == '+')
5029 *flags |= ENV_ACT_SETABSENT;
5030 else if (*cptr == '-')
5031 *flags |= ENV_ACT_REMOVE;
5032 else if (*cptr == '!')
5033 *flags |= ENV_ACT_REMOVEMATCH;
5034 else if (*cptr == '*')
5035 *flags |= ENV_MOD_MACHINE;
5036 else
5037 break;
5039 cptr++;
5040 (*name)++;
5043 if (!*cptr)
5045 ERR("Missing environment variable\n");
5046 return ERROR_FUNCTION_FAILED;
5049 if (!strncmpW(ptr, prefix, prefix_len))
5051 *flags |= ENV_MOD_APPEND;
5052 *value += lstrlenW(prefix);
5054 else if (lstrlenW(*value) >= prefix_len)
5056 ptr += lstrlenW(ptr) - prefix_len;
5057 if (!lstrcmpW(ptr, prefix))
5059 *flags |= ENV_MOD_PREFIX;
5060 /* the "[~]" will be removed by deformat_string */;
5064 if (!*flags ||
5065 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5066 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5067 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5068 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5070 ERR("Invalid flags: %08x\n", *flags);
5071 return ERROR_FUNCTION_FAILED;
5074 return ERROR_SUCCESS;
5077 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5079 MSIPACKAGE *package = param;
5080 LPCWSTR name, value;
5081 LPWSTR data = NULL, newval = NULL;
5082 LPWSTR deformatted = NULL, ptr;
5083 DWORD flags, type, size;
5084 LONG res;
5085 HKEY env = NULL, root;
5086 LPCWSTR environment;
5088 static const WCHAR user_env[] =
5089 {'E','n','v','i','r','o','n','m','e','n','t',0};
5090 static const WCHAR machine_env[] =
5091 {'S','y','s','t','e','m','\\',
5092 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5093 'C','o','n','t','r','o','l','\\',
5094 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5095 'E','n','v','i','r','o','n','m','e','n','t',0};
5096 static const WCHAR semicolon[] = {';',0};
5098 name = MSI_RecordGetString(rec, 2);
5099 value = MSI_RecordGetString(rec, 3);
5101 res = env_set_flags(&name, &value, &flags);
5102 if (res != ERROR_SUCCESS)
5103 goto done;
5105 deformat_string(package, value, &deformatted);
5106 if (!deformatted)
5108 res = ERROR_OUTOFMEMORY;
5109 goto done;
5112 value = deformatted;
5114 if (flags & ENV_MOD_MACHINE)
5116 environment = machine_env;
5117 root = HKEY_LOCAL_MACHINE;
5119 else
5121 environment = user_env;
5122 root = HKEY_CURRENT_USER;
5125 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5126 KEY_ALL_ACCESS, NULL, &env, NULL);
5127 if (res != ERROR_SUCCESS)
5128 goto done;
5130 if (flags & ENV_ACT_REMOVE)
5131 FIXME("Not removing environment variable on uninstall!\n");
5133 size = 0;
5134 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5135 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5136 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5137 goto done;
5139 if (res != ERROR_FILE_NOT_FOUND)
5141 if (flags & ENV_ACT_SETABSENT)
5143 res = ERROR_SUCCESS;
5144 goto done;
5147 data = msi_alloc(size);
5148 if (!data)
5150 RegCloseKey(env);
5151 return ERROR_OUTOFMEMORY;
5154 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5155 if (res != ERROR_SUCCESS)
5156 goto done;
5158 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5160 res = RegDeleteKeyW(env, name);
5161 goto done;
5164 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5165 newval = msi_alloc(size);
5166 ptr = newval;
5167 if (!newval)
5169 res = ERROR_OUTOFMEMORY;
5170 goto done;
5173 if (!(flags & ENV_MOD_MASK))
5174 lstrcpyW(newval, value);
5175 else
5177 if (flags & ENV_MOD_PREFIX)
5179 lstrcpyW(newval, value);
5180 lstrcatW(newval, semicolon);
5181 ptr = newval + lstrlenW(value) + 1;
5184 lstrcpyW(ptr, data);
5186 if (flags & ENV_MOD_APPEND)
5188 lstrcatW(newval, semicolon);
5189 lstrcatW(newval, value);
5193 else
5195 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5196 newval = msi_alloc(size);
5197 if (!newval)
5199 res = ERROR_OUTOFMEMORY;
5200 goto done;
5203 lstrcpyW(newval, value);
5206 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5207 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5209 done:
5210 if (env) RegCloseKey(env);
5211 msi_free(deformatted);
5212 msi_free(data);
5213 msi_free(newval);
5214 return res;
5217 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5219 UINT rc;
5220 MSIQUERY * view;
5221 static const WCHAR ExecSeqQuery[] =
5222 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5223 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5224 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5225 if (rc != ERROR_SUCCESS)
5226 return ERROR_SUCCESS;
5228 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5229 msiobj_release(&view->hdr);
5231 return rc;
5234 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5236 typedef struct
5238 struct list entry;
5239 LPWSTR sourcename;
5240 LPWSTR destname;
5241 LPWSTR source;
5242 LPWSTR dest;
5243 } FILE_LIST;
5245 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5247 BOOL ret;
5249 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5250 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5252 WARN("Source or dest is directory, not moving\n");
5253 return FALSE;
5256 if (options == msidbMoveFileOptionsMove)
5258 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5259 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5260 if (!ret)
5262 WARN("MoveFile failed: %d\n", GetLastError());
5263 return FALSE;
5266 else
5268 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5269 ret = CopyFileW(source, dest, FALSE);
5270 if (!ret)
5272 WARN("CopyFile failed: %d\n", GetLastError());
5273 return FALSE;
5277 return TRUE;
5280 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5282 LPWSTR path, ptr;
5283 DWORD dirlen, pathlen;
5285 ptr = strrchrW(wildcard, '\\');
5286 dirlen = ptr - wildcard + 1;
5288 pathlen = dirlen + lstrlenW(filename) + 1;
5289 path = msi_alloc(pathlen * sizeof(WCHAR));
5291 lstrcpynW(path, wildcard, dirlen + 1);
5292 lstrcatW(path, filename);
5294 return path;
5297 static void free_file_entry(FILE_LIST *file)
5299 msi_free(file->source);
5300 msi_free(file->dest);
5301 msi_free(file);
5304 static void free_list(FILE_LIST *list)
5306 while (!list_empty(&list->entry))
5308 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5310 list_remove(&file->entry);
5311 free_file_entry(file);
5315 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5317 FILE_LIST *new, *file;
5318 LPWSTR ptr, filename;
5319 DWORD size;
5321 new = msi_alloc_zero(sizeof(FILE_LIST));
5322 if (!new)
5323 return FALSE;
5325 new->source = strdupW(source);
5326 ptr = strrchrW(dest, '\\') + 1;
5327 filename = strrchrW(new->source, '\\') + 1;
5329 new->sourcename = filename;
5331 if (*ptr)
5332 new->destname = ptr;
5333 else
5334 new->destname = new->sourcename;
5336 size = (ptr - dest) + lstrlenW(filename) + 1;
5337 new->dest = msi_alloc(size * sizeof(WCHAR));
5338 if (!new->dest)
5340 free_file_entry(new);
5341 return FALSE;
5344 lstrcpynW(new->dest, dest, ptr - dest + 1);
5345 lstrcatW(new->dest, filename);
5347 if (list_empty(&files->entry))
5349 list_add_head(&files->entry, &new->entry);
5350 return TRUE;
5353 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5355 if (lstrcmpW(source, file->source) < 0)
5357 list_add_before(&file->entry, &new->entry);
5358 return TRUE;
5362 list_add_after(&file->entry, &new->entry);
5363 return TRUE;
5366 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5368 WIN32_FIND_DATAW wfd;
5369 HANDLE hfile;
5370 LPWSTR path;
5371 BOOL res;
5372 FILE_LIST files, *file;
5373 DWORD size;
5375 hfile = FindFirstFileW(source, &wfd);
5376 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5378 list_init(&files.entry);
5380 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5382 if (is_dot_dir(wfd.cFileName)) continue;
5384 path = wildcard_to_file(source, wfd.cFileName);
5385 if (!path)
5387 res = FALSE;
5388 goto done;
5391 add_wildcard(&files, path, dest);
5392 msi_free(path);
5395 /* no files match the wildcard */
5396 if (list_empty(&files.entry))
5397 goto done;
5399 /* only the first wildcard match gets renamed to dest */
5400 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5401 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5402 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5403 if (!file->dest)
5405 res = FALSE;
5406 goto done;
5409 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5411 while (!list_empty(&files.entry))
5413 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5415 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5417 list_remove(&file->entry);
5418 free_file_entry(file);
5421 res = TRUE;
5423 done:
5424 free_list(&files);
5425 FindClose(hfile);
5426 return res;
5429 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5431 MSIPACKAGE *package = param;
5432 MSICOMPONENT *comp;
5433 LPCWSTR sourcename, destname;
5434 LPWSTR sourcedir = NULL, destdir = NULL;
5435 LPWSTR source = NULL, dest = NULL;
5436 int options;
5437 DWORD size;
5438 BOOL ret, wildcards;
5440 static const WCHAR backslash[] = {'\\',0};
5442 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5443 if (!comp || !comp->Enabled ||
5444 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5446 TRACE("Component not set for install, not moving file\n");
5447 return ERROR_SUCCESS;
5450 sourcename = MSI_RecordGetString(rec, 3);
5451 destname = MSI_RecordGetString(rec, 4);
5452 options = MSI_RecordGetInteger(rec, 7);
5454 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5455 if (!sourcedir)
5456 goto done;
5458 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5459 if (!destdir)
5460 goto done;
5462 if (!sourcename)
5464 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5465 goto done;
5467 source = strdupW(sourcedir);
5468 if (!source)
5469 goto done;
5471 else
5473 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5474 source = msi_alloc(size * sizeof(WCHAR));
5475 if (!source)
5476 goto done;
5478 lstrcpyW(source, sourcedir);
5479 if (source[lstrlenW(source) - 1] != '\\')
5480 lstrcatW(source, backslash);
5481 lstrcatW(source, sourcename);
5484 wildcards = strchrW(source, '*') || strchrW(source, '?');
5486 if (!destname && !wildcards)
5488 destname = strdupW(sourcename);
5489 if (!destname)
5490 goto done;
5493 size = 0;
5494 if (destname)
5495 size = lstrlenW(destname);
5497 size += lstrlenW(destdir) + 2;
5498 dest = msi_alloc(size * sizeof(WCHAR));
5499 if (!dest)
5500 goto done;
5502 lstrcpyW(dest, destdir);
5503 if (dest[lstrlenW(dest) - 1] != '\\')
5504 lstrcatW(dest, backslash);
5506 if (destname)
5507 lstrcatW(dest, destname);
5509 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5511 ret = CreateDirectoryW(destdir, NULL);
5512 if (!ret)
5514 WARN("CreateDirectory failed: %d\n", GetLastError());
5515 return ERROR_SUCCESS;
5519 if (!wildcards)
5520 msi_move_file(source, dest, options);
5521 else
5522 move_files_wildcard(source, dest, options);
5524 done:
5525 msi_free(sourcedir);
5526 msi_free(destdir);
5527 msi_free(source);
5528 msi_free(dest);
5530 return ERROR_SUCCESS;
5533 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5535 UINT rc;
5536 MSIQUERY *view;
5538 static const WCHAR ExecSeqQuery[] =
5539 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5540 '`','M','o','v','e','F','i','l','e','`',0};
5542 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5543 if (rc != ERROR_SUCCESS)
5544 return ERROR_SUCCESS;
5546 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5547 msiobj_release(&view->hdr);
5549 return rc;
5552 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5553 DWORD dwReserved);
5554 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5555 LPVOID pvReserved, HMODULE *phModDll);
5557 static BOOL init_functionpointers(void)
5559 HRESULT hr;
5560 HMODULE hfusion;
5561 HMODULE hmscoree;
5563 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5565 hmscoree = LoadLibraryA("mscoree.dll");
5566 if (!hmscoree)
5568 WARN("mscoree.dll not available\n");
5569 return FALSE;
5572 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5573 if (!pLoadLibraryShim)
5575 WARN("LoadLibraryShim not available\n");
5576 FreeLibrary(hmscoree);
5577 return FALSE;
5580 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5581 if (FAILED(hr))
5583 WARN("fusion.dll not available\n");
5584 FreeLibrary(hmscoree);
5585 return FALSE;
5588 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5590 FreeLibrary(hmscoree);
5591 return TRUE;
5594 static UINT install_assembly(LPWSTR path)
5596 IAssemblyCache *cache;
5597 HRESULT hr;
5598 UINT r = ERROR_FUNCTION_FAILED;
5600 if (!init_functionpointers() || !pCreateAssemblyCache)
5601 return ERROR_FUNCTION_FAILED;
5603 hr = pCreateAssemblyCache(&cache, 0);
5604 if (FAILED(hr))
5605 goto done;
5607 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5608 if (FAILED(hr))
5609 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5611 r = ERROR_SUCCESS;
5613 done:
5614 IAssemblyCache_Release(cache);
5615 return r;
5618 static UINT ITERATE_PublishAssembly( MSIRECORD *rec, LPVOID param )
5620 MSIPACKAGE *package = param;
5621 MSICOMPONENT *comp;
5622 MSIFEATURE *feature;
5623 MSIFILE *file;
5624 WCHAR path[MAX_PATH];
5625 LPCWSTR app;
5626 DWORD attr;
5627 UINT r;
5629 comp = get_loaded_component(package, MSI_RecordGetString(rec, 1));
5630 if (!comp || !comp->Enabled ||
5631 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5633 ERR("Component not set for install, not publishing assembly\n");
5634 return ERROR_SUCCESS;
5637 feature = find_feature_by_name(package, MSI_RecordGetString(rec, 2));
5638 if (feature)
5639 msi_feature_set_state(feature, INSTALLSTATE_LOCAL);
5641 if (MSI_RecordGetString(rec, 3))
5642 FIXME("Manifest unhandled\n");
5644 app = MSI_RecordGetString(rec, 4);
5645 if (app)
5647 FIXME("Assembly should be privately installed\n");
5648 return ERROR_SUCCESS;
5651 attr = MSI_RecordGetInteger(rec, 5);
5652 if (attr == msidbAssemblyAttributesWin32)
5654 FIXME("Win32 assemblies not handled\n");
5655 return ERROR_SUCCESS;
5658 /* FIXME: extract all files belonging to this component */
5659 file = msi_find_file(package, comp->KeyPath);
5661 GetTempPathW(MAX_PATH, path);
5662 r = msi_extract_file(package, file, path);
5663 if (r != ERROR_SUCCESS)
5665 ERR("Failed to extract temporary assembly\n");
5666 return r;
5669 PathAddBackslashW(path);
5670 lstrcatW(path, file->FileName);
5672 r = install_assembly(path);
5673 if (r != ERROR_SUCCESS)
5674 ERR("Failed to install assembly\n");
5676 /* FIXME: write Installer assembly reg values */
5678 return r;
5681 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5683 UINT rc;
5684 MSIQUERY *view;
5686 static const WCHAR ExecSeqQuery[] =
5687 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5688 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5690 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5691 if (rc != ERROR_SUCCESS)
5692 return ERROR_SUCCESS;
5694 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishAssembly, package);
5695 msiobj_release(&view->hdr);
5697 return rc;
5700 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5701 LPCSTR action, LPCWSTR table )
5703 static const WCHAR query[] = {
5704 'S','E','L','E','C','T',' ','*',' ',
5705 'F','R','O','M',' ','`','%','s','`',0 };
5706 MSIQUERY *view = NULL;
5707 DWORD count = 0;
5708 UINT r;
5710 r = MSI_OpenQuery( package->db, &view, query, table );
5711 if (r == ERROR_SUCCESS)
5713 r = MSI_IterateRecords(view, &count, NULL, package);
5714 msiobj_release(&view->hdr);
5717 if (count)
5718 FIXME("%s -> %u ignored %s table values\n",
5719 action, count, debugstr_w(table));
5721 return ERROR_SUCCESS;
5724 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5726 TRACE("%p\n", package);
5727 return ERROR_SUCCESS;
5730 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
5732 static const WCHAR table[] =
5733 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5734 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
5737 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5739 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5740 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5743 static UINT ACTION_BindImage( MSIPACKAGE *package )
5745 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5746 return msi_unimplemented_action_stub( package, "BindImage", table );
5749 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5751 static const WCHAR table[] = {
5752 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
5753 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5756 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5758 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5759 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5762 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5764 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5765 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5768 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5770 static const WCHAR table[] = {
5771 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5772 return msi_unimplemented_action_stub( package, "DeleteServices", table );
5774 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5776 static const WCHAR table[] = {
5777 'P','r','o','d','u','c','t','I','D',0 };
5778 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5781 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5783 static const WCHAR table[] = {
5784 'E','n','v','i','r','o','n','m','e','n','t',0 };
5785 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5788 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5790 static const WCHAR table[] = {
5791 'M','s','i','A','s','s','e','m','b','l','y',0 };
5792 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5795 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5797 static const WCHAR table[] = { 'F','o','n','t',0 };
5798 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5801 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5803 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5804 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5807 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5809 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5810 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5813 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5815 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5816 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5819 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5821 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5822 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5825 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5827 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5828 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5831 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5833 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5834 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5837 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5839 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5840 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5843 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5845 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5846 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5849 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5851 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5852 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5855 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5857 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5858 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5861 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5863 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5864 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5867 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5869 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5870 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5873 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5875 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5876 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5879 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5881 static const WCHAR table[] = { 'M','I','M','E',0 };
5882 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5885 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5887 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5888 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5891 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5893 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5894 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5897 static const struct _actions StandardActions[] = {
5898 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
5899 { szAppSearch, ACTION_AppSearch },
5900 { szBindImage, ACTION_BindImage },
5901 { szCCPSearch, ACTION_CCPSearch },
5902 { szCostFinalize, ACTION_CostFinalize },
5903 { szCostInitialize, ACTION_CostInitialize },
5904 { szCreateFolders, ACTION_CreateFolders },
5905 { szCreateShortcuts, ACTION_CreateShortcuts },
5906 { szDeleteServices, ACTION_DeleteServices },
5907 { szDisableRollback, NULL },
5908 { szDuplicateFiles, ACTION_DuplicateFiles },
5909 { szExecuteAction, ACTION_ExecuteAction },
5910 { szFileCost, ACTION_FileCost },
5911 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5912 { szForceReboot, ACTION_ForceReboot },
5913 { szInstallAdminPackage, NULL },
5914 { szInstallExecute, ACTION_InstallExecute },
5915 { szInstallExecuteAgain, ACTION_InstallExecute },
5916 { szInstallFiles, ACTION_InstallFiles},
5917 { szInstallFinalize, ACTION_InstallFinalize },
5918 { szInstallInitialize, ACTION_InstallInitialize },
5919 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
5920 { szInstallValidate, ACTION_InstallValidate },
5921 { szIsolateComponents, ACTION_IsolateComponents },
5922 { szLaunchConditions, ACTION_LaunchConditions },
5923 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5924 { szMoveFiles, ACTION_MoveFiles },
5925 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5926 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
5927 { szInstallODBC, ACTION_InstallODBC },
5928 { szInstallServices, ACTION_InstallServices },
5929 { szPatchFiles, ACTION_PatchFiles },
5930 { szProcessComponents, ACTION_ProcessComponents },
5931 { szPublishComponents, ACTION_PublishComponents },
5932 { szPublishFeatures, ACTION_PublishFeatures },
5933 { szPublishProduct, ACTION_PublishProduct },
5934 { szRegisterClassInfo, ACTION_RegisterClassInfo },
5935 { szRegisterComPlus, ACTION_RegisterComPlus},
5936 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5937 { szRegisterFonts, ACTION_RegisterFonts },
5938 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5939 { szRegisterProduct, ACTION_RegisterProduct },
5940 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5941 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
5942 { szRegisterUser, ACTION_RegisterUser },
5943 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
5944 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
5945 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5946 { szRemoveFiles, ACTION_RemoveFiles },
5947 { szRemoveFolders, ACTION_RemoveFolders },
5948 { szRemoveIniValues, ACTION_RemoveIniValues },
5949 { szRemoveODBC, ACTION_RemoveODBC },
5950 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5951 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5952 { szResolveSource, ACTION_ResolveSource },
5953 { szRMCCPSearch, ACTION_RMCCPSearch },
5954 { szScheduleReboot, NULL },
5955 { szSelfRegModules, ACTION_SelfRegModules },
5956 { szSelfUnregModules, ACTION_SelfUnregModules },
5957 { szSetODBCFolders, NULL },
5958 { szStartServices, ACTION_StartServices },
5959 { szStopServices, ACTION_StopServices },
5960 { szUnpublishComponents, ACTION_UnpublishComponents },
5961 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5962 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5963 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5964 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
5965 { szUnregisterFonts, ACTION_UnregisterFonts },
5966 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5967 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5968 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5969 { szValidateProductID, ACTION_ValidateProductID },
5970 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5971 { szWriteIniValues, ACTION_WriteIniValues },
5972 { szWriteRegistryValues, ACTION_WriteRegistryValues },
5973 { NULL, NULL },
5976 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
5977 UINT* rc, BOOL force )
5979 BOOL ret = FALSE;
5980 BOOL run = force;
5981 int i;
5983 if (!run && !package->script->CurrentlyScripting)
5984 run = TRUE;
5986 if (!run)
5988 if (strcmpW(action,szInstallFinalize) == 0 ||
5989 strcmpW(action,szInstallExecute) == 0 ||
5990 strcmpW(action,szInstallExecuteAgain) == 0)
5991 run = TRUE;
5994 i = 0;
5995 while (StandardActions[i].action != NULL)
5997 if (strcmpW(StandardActions[i].action, action)==0)
5999 if (!run)
6001 ui_actioninfo(package, action, TRUE, 0);
6002 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6003 ui_actioninfo(package, action, FALSE, *rc);
6005 else
6007 ui_actionstart(package, action);
6008 if (StandardActions[i].handler)
6010 *rc = StandardActions[i].handler(package);
6012 else
6014 FIXME("unhandled standard action %s\n",debugstr_w(action));
6015 *rc = ERROR_SUCCESS;
6018 ret = TRUE;
6019 break;
6021 i++;
6023 return ret;