includes: Fix alignment for 64-bits
[wine/wine64.git] / dlls / msi / action.c
blob3a32a064c955b337bbde9c8aa32165eb3474fcd9
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,
292 BOOL preserve_case )
294 LPCWSTR ptr,ptr2;
295 BOOL quote;
296 DWORD len;
297 LPWSTR prop = NULL, val = NULL;
299 if (!szCommandLine)
300 return ERROR_SUCCESS;
302 ptr = szCommandLine;
304 while (*ptr)
306 if (*ptr==' ')
308 ptr++;
309 continue;
312 TRACE("Looking at %s\n",debugstr_w(ptr));
314 ptr2 = strchrW(ptr,'=');
315 if (!ptr2)
317 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
318 break;
321 quote = FALSE;
323 len = ptr2-ptr;
324 prop = msi_alloc((len+1)*sizeof(WCHAR));
325 memcpy(prop,ptr,len*sizeof(WCHAR));
326 prop[len]=0;
328 if (!preserve_case)
329 struprW(prop);
331 ptr2++;
333 len = 0;
334 ptr = ptr2;
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
337 if (*ptr == '"')
338 quote = !quote;
339 ptr++;
340 len++;
343 if (*ptr2=='"')
345 ptr2++;
346 len -= 2;
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
350 val[len] = 0;
352 if (lstrlenW(prop) > 0)
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
358 msi_free(val);
359 msi_free(prop);
362 return ERROR_SUCCESS;
366 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
368 LPCWSTR pc;
369 LPWSTR p, *ret = NULL;
370 UINT count = 0;
372 if (!str)
373 return ret;
375 /* count the number of substrings */
376 for ( pc = str, count = 0; pc; count++ )
378 pc = strchrW( pc, sep );
379 if (pc)
380 pc++;
383 /* allocate space for an array of substring pointers and the substrings */
384 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
385 (lstrlenW(str)+1) * sizeof(WCHAR) );
386 if (!ret)
387 return ret;
389 /* copy the string and set the pointers */
390 p = (LPWSTR) &ret[count+1];
391 lstrcpyW( p, str );
392 for( count = 0; (ret[count] = p); count++ )
394 p = strchrW( p, sep );
395 if (p)
396 *p++ = 0;
399 return ret;
402 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
404 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code, patch_product;
406 UINT ret;
408 prod_code = msi_dup_property( package, szProductCode );
409 patch_product = msi_get_suminfo_product( patch );
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
413 if ( strstrW( patch_product, prod_code ) )
414 ret = ERROR_SUCCESS;
415 else
416 ret = ERROR_FUNCTION_FAILED;
418 msi_free( patch_product );
419 msi_free( prod_code );
421 return ret;
424 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
425 MSIDATABASE *patch_db, LPCWSTR name )
427 UINT ret = ERROR_FUNCTION_FAILED;
428 IStorage *stg = NULL;
429 HRESULT r;
431 TRACE("%p %s\n", package, debugstr_w(name) );
433 if (*name++ != ':')
435 ERR("expected a colon in %s\n", debugstr_w(name));
436 return ERROR_FUNCTION_FAILED;
439 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
440 if (SUCCEEDED(r))
442 ret = msi_check_transform_applicable( package, stg );
443 if (ret == ERROR_SUCCESS)
444 msi_table_apply_transform( package->db, stg );
445 else
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
447 IStorage_Release( stg );
449 else
450 ERR("failed to open substorage %s\n", debugstr_w(name));
452 return ERROR_SUCCESS;
455 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
457 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list, *guids, product_code;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
461 product_code = msi_dup_property( package, szProdCode );
462 if (!product_code)
464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
466 return ERROR_SUCCESS;
469 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
470 guids = msi_split_string( guid_list, ';' );
471 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
473 if (!lstrcmpW( guids[i], product_code ))
474 ret = ERROR_SUCCESS;
476 msi_free( guids );
477 msi_free( guid_list );
478 msi_free( product_code );
480 return ret;
483 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
485 MSIQUERY *view;
486 MSIRECORD *rec = NULL;
487 LPWSTR patch;
488 LPCWSTR prop;
489 UINT r;
491 static const WCHAR szPatch[] = {'P','A','T','C','H',0};
492 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
493 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
494 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
495 '`','S','o','u','r','c','e','`',' ','I','S',' ',
496 'N','O','T',' ','N','U','L','L',0};
498 r = MSI_DatabaseOpenViewW(package->db, query, &view);
499 if (r != ERROR_SUCCESS)
500 return r;
502 r = MSI_ViewExecute(view, 0);
503 if (r != ERROR_SUCCESS)
504 goto done;
506 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
508 prop = MSI_RecordGetString(rec, 1);
509 patch = msi_dup_property(package, szPatch);
510 MSI_SetPropertyW(package, prop, patch);
511 msi_free(patch);
514 done:
515 if (rec) msiobj_release(&rec->hdr);
516 msiobj_release(&view->hdr);
518 return r;
521 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
523 MSISUMMARYINFO *si;
524 LPWSTR str, *substorage;
525 UINT i, r = ERROR_SUCCESS;
527 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
528 if (!si)
529 return ERROR_FUNCTION_FAILED;
531 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
533 TRACE("Patch not applicable\n");
534 return ERROR_SUCCESS;
537 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
538 if (!package->patch)
539 return ERROR_OUTOFMEMORY;
541 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
542 if (!package->patch->patchcode)
543 return ERROR_OUTOFMEMORY;
545 /* enumerate the substorage */
546 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
547 package->patch->transforms = str;
549 substorage = msi_split_string( str, ';' );
550 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
551 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
553 msi_free( substorage );
554 msiobj_release( &si->hdr );
556 msi_set_media_source_prop(package);
558 return r;
561 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
563 MSIDATABASE *patch_db = NULL;
564 UINT r;
566 TRACE("%p %s\n", package, debugstr_w( file ) );
568 /* FIXME:
569 * We probably want to make sure we only open a patch collection here.
570 * Patch collections (.msp) and databases (.msi) have different GUIDs
571 * but currently MSI_OpenDatabaseW will accept both.
573 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
574 if ( r != ERROR_SUCCESS )
576 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
577 return r;
580 msi_parse_patch_summary( package, patch_db );
583 * There might be a CAB file in the patch package,
584 * so append it to the list of storage to search for streams.
586 append_storage_to_db( package->db, patch_db->storage );
588 msiobj_release( &patch_db->hdr );
590 return ERROR_SUCCESS;
593 /* get the PATCH property, and apply all the patches it specifies */
594 static UINT msi_apply_patches( MSIPACKAGE *package )
596 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
597 LPWSTR patch_list, *patches;
598 UINT i, r = ERROR_SUCCESS;
600 patch_list = msi_dup_property( package, szPatch );
602 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
604 patches = msi_split_string( patch_list, ';' );
605 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
606 r = msi_apply_patch_package( package, patches[i] );
608 msi_free( patches );
609 msi_free( patch_list );
611 return r;
614 static UINT msi_apply_transforms( MSIPACKAGE *package )
616 static const WCHAR szTransforms[] = {
617 'T','R','A','N','S','F','O','R','M','S',0 };
618 LPWSTR xform_list, *xforms;
619 UINT i, r = ERROR_SUCCESS;
621 xform_list = msi_dup_property( package, szTransforms );
622 xforms = msi_split_string( xform_list, ';' );
624 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
626 if (xforms[i][0] == ':')
627 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
628 else
629 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
632 msi_free( xforms );
633 msi_free( xform_list );
635 return r;
638 static BOOL ui_sequence_exists( MSIPACKAGE *package )
640 MSIQUERY *view;
641 UINT rc;
643 static const WCHAR ExecSeqQuery [] =
644 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
645 '`','I','n','s','t','a','l','l',
646 'U','I','S','e','q','u','e','n','c','e','`',
647 ' ','W','H','E','R','E',' ',
648 '`','S','e','q','u','e','n','c','e','`',' ',
649 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
650 '`','S','e','q','u','e','n','c','e','`',0};
652 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
653 if (rc == ERROR_SUCCESS)
655 msiobj_release(&view->hdr);
656 return TRUE;
659 return FALSE;
662 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
664 LPWSTR p, db;
665 LPWSTR source, check;
666 DWORD len;
668 static const WCHAR szOriginalDatabase[] =
669 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
671 db = msi_dup_property( package, szOriginalDatabase );
672 if (!db)
673 return ERROR_OUTOFMEMORY;
675 p = strrchrW( db, '\\' );
676 if (!p)
678 p = strrchrW( db, '/' );
679 if (!p)
681 msi_free(db);
682 return ERROR_SUCCESS;
686 len = p - db + 2;
687 source = msi_alloc( len * sizeof(WCHAR) );
688 lstrcpynW( source, db, len );
690 check = msi_dup_property( package, cszSourceDir );
691 if (!check || replace)
692 MSI_SetPropertyW( package, cszSourceDir, source );
694 msi_free( check );
696 check = msi_dup_property( package, cszSOURCEDIR );
697 if (!check || replace)
698 MSI_SetPropertyW( package, cszSOURCEDIR, source );
700 msi_free( check );
701 msi_free( source );
702 msi_free( db );
704 return ERROR_SUCCESS;
707 static UINT msi_set_context(MSIPACKAGE *package)
709 WCHAR val[10];
710 DWORD sz = 10;
711 DWORD num;
712 UINT r;
714 static const WCHAR szOne[] = {'1',0};
715 static const WCHAR szAllUsers[] = {'A','L','L','U','S','E','R','S',0};
717 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
719 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
720 if (r == ERROR_SUCCESS)
722 num = atolW(val);
723 if (num == 1 || num == 2)
724 package->Context = MSIINSTALLCONTEXT_MACHINE;
727 MSI_SetPropertyW(package, szAllUsers, szOne);
728 return ERROR_SUCCESS;
731 /****************************************************
732 * TOP level entry points
733 *****************************************************/
735 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
736 LPCWSTR szCommandLine )
738 UINT rc;
739 BOOL ui = FALSE, ui_exists;
740 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
741 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
742 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
744 MSI_SetPropertyW(package, szAction, szInstall);
746 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
748 package->script->InWhatSequence = SEQUENCE_INSTALL;
750 if (szPackagePath)
752 LPWSTR p, dir;
753 LPCWSTR file;
755 dir = strdupW(szPackagePath);
756 p = strrchrW(dir, '\\');
757 if (p)
759 *(++p) = 0;
760 file = szPackagePath + (p - dir);
762 else
764 msi_free(dir);
765 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
766 GetCurrentDirectoryW(MAX_PATH, dir);
767 lstrcatW(dir, cszbs);
768 file = szPackagePath;
771 msi_free( package->PackagePath );
772 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
773 if (!package->PackagePath)
775 msi_free(dir);
776 return ERROR_OUTOFMEMORY;
779 lstrcpyW(package->PackagePath, dir);
780 lstrcatW(package->PackagePath, file);
781 msi_free(dir);
783 msi_set_sourcedir_props(package, FALSE);
786 msi_parse_command_line( package, szCommandLine, FALSE );
788 msi_apply_transforms( package );
789 msi_apply_patches( package );
791 /* properties may have been added by a transform */
792 msi_clone_properties( package );
793 msi_set_context( package );
795 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
797 package->script->InWhatSequence |= SEQUENCE_UI;
798 rc = ACTION_ProcessUISequence(package);
799 ui = TRUE;
800 ui_exists = ui_sequence_exists(package);
801 if (rc == ERROR_SUCCESS || !ui_exists)
803 package->script->InWhatSequence |= SEQUENCE_EXEC;
804 rc = ACTION_ProcessExecSequence(package,ui_exists);
807 else
808 rc = ACTION_ProcessExecSequence(package,FALSE);
810 package->script->CurrentlyScripting= FALSE;
812 /* process the ending type action */
813 if (rc == ERROR_SUCCESS)
814 ACTION_PerformActionSequence(package,-1,ui);
815 else if (rc == ERROR_INSTALL_USEREXIT)
816 ACTION_PerformActionSequence(package,-2,ui);
817 else if (rc == ERROR_INSTALL_SUSPEND)
818 ACTION_PerformActionSequence(package,-4,ui);
819 else /* failed */
820 ACTION_PerformActionSequence(package,-3,ui);
822 /* finish up running custom actions */
823 ACTION_FinishCustomActions(package);
825 return rc;
828 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
830 UINT rc = ERROR_SUCCESS;
831 MSIRECORD * row = 0;
832 static const WCHAR ExecSeqQuery[] =
833 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
834 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
835 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
836 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
838 static const WCHAR UISeqQuery[] =
839 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
840 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
841 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
842 ' ', '=',' ','%','i',0};
844 if (UI)
845 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
846 else
847 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
849 if (row)
851 LPCWSTR action, cond;
853 TRACE("Running the actions\n");
855 /* check conditions */
856 cond = MSI_RecordGetString(row,2);
858 /* this is a hack to skip errors in the condition code */
859 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
860 goto end;
862 action = MSI_RecordGetString(row,1);
863 if (!action)
865 ERR("failed to fetch action\n");
866 rc = ERROR_FUNCTION_FAILED;
867 goto end;
870 if (UI)
871 rc = ACTION_PerformUIAction(package,action,-1);
872 else
873 rc = ACTION_PerformAction(package,action,-1,FALSE);
874 end:
875 msiobj_release(&row->hdr);
877 else
878 rc = ERROR_SUCCESS;
880 return rc;
883 typedef struct {
884 MSIPACKAGE* package;
885 BOOL UI;
886 } iterate_action_param;
888 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
890 iterate_action_param *iap= (iterate_action_param*)param;
891 UINT rc;
892 LPCWSTR cond, action;
894 action = MSI_RecordGetString(row,1);
895 if (!action)
897 ERR("Error is retrieving action name\n");
898 return ERROR_FUNCTION_FAILED;
901 /* check conditions */
902 cond = MSI_RecordGetString(row,2);
904 /* this is a hack to skip errors in the condition code */
905 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
907 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
908 return ERROR_SUCCESS;
911 if (iap->UI)
912 rc = ACTION_PerformUIAction(iap->package,action,-1);
913 else
914 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
916 msi_dialog_check_messages( NULL );
918 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
919 rc = iap->package->CurrentInstallState;
921 if (rc == ERROR_FUNCTION_NOT_CALLED)
922 rc = ERROR_SUCCESS;
924 if (rc != ERROR_SUCCESS)
925 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
927 return rc;
930 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
932 MSIQUERY * view;
933 UINT r;
934 static const WCHAR query[] =
935 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
936 '`','%','s','`',
937 ' ','W','H','E','R','E',' ',
938 '`','S','e','q','u','e','n','c','e','`',' ',
939 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
940 '`','S','e','q','u','e','n','c','e','`',0};
941 iterate_action_param iap;
944 * FIXME: probably should be checking UILevel in the
945 * ACTION_PerformUIAction/ACTION_PerformAction
946 * rather than saving the UI level here. Those
947 * two functions can be merged too.
949 iap.package = package;
950 iap.UI = TRUE;
952 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
954 r = MSI_OpenQuery( package->db, &view, query, szTable );
955 if (r == ERROR_SUCCESS)
957 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
958 msiobj_release(&view->hdr);
961 return r;
964 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
966 MSIQUERY * view;
967 UINT rc;
968 static const WCHAR ExecSeqQuery[] =
969 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
970 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
971 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
972 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
973 'O','R','D','E','R',' ', 'B','Y',' ',
974 '`','S','e','q','u','e','n','c','e','`',0 };
975 MSIRECORD * row = 0;
976 static const WCHAR IVQuery[] =
977 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
978 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
979 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
980 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
981 ' ','\'', 'I','n','s','t','a','l','l',
982 'V','a','l','i','d','a','t','e','\'', 0};
983 INT seq = 0;
984 iterate_action_param iap;
986 iap.package = package;
987 iap.UI = FALSE;
989 if (package->script->ExecuteSequenceRun)
991 TRACE("Execute Sequence already Run\n");
992 return ERROR_SUCCESS;
995 package->script->ExecuteSequenceRun = TRUE;
997 /* get the sequence number */
998 if (UIran)
1000 row = MSI_QueryGetRecord(package->db, IVQuery);
1001 if( !row )
1002 return ERROR_FUNCTION_FAILED;
1003 seq = MSI_RecordGetInteger(row,1);
1004 msiobj_release(&row->hdr);
1007 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1008 if (rc == ERROR_SUCCESS)
1010 TRACE("Running the actions\n");
1012 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
1013 msiobj_release(&view->hdr);
1016 return rc;
1019 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1021 MSIQUERY * view;
1022 UINT rc;
1023 static const WCHAR ExecSeqQuery [] =
1024 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1025 '`','I','n','s','t','a','l','l',
1026 'U','I','S','e','q','u','e','n','c','e','`',
1027 ' ','W','H','E','R','E',' ',
1028 '`','S','e','q','u','e','n','c','e','`',' ',
1029 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1030 '`','S','e','q','u','e','n','c','e','`',0};
1031 iterate_action_param iap;
1033 iap.package = package;
1034 iap.UI = TRUE;
1036 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1038 if (rc == ERROR_SUCCESS)
1040 TRACE("Running the actions\n");
1042 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
1043 msiobj_release(&view->hdr);
1046 return rc;
1049 /********************************************************
1050 * ACTION helper functions and functions that perform the actions
1051 *******************************************************/
1052 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1053 UINT* rc, UINT script, BOOL force )
1055 BOOL ret=FALSE;
1056 UINT arc;
1058 arc = ACTION_CustomAction(package, action, script, force);
1060 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1062 *rc = arc;
1063 ret = TRUE;
1065 return ret;
1069 * A lot of actions are really important even if they don't do anything
1070 * explicit... Lots of properties are set at the beginning of the installation
1071 * CostFinalize does a bunch of work to translate the directories and such
1073 * But until I get write access to the database that is hard, so I am going to
1074 * hack it to see if I can get something to run.
1076 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
1078 UINT rc = ERROR_SUCCESS;
1079 BOOL handled;
1081 TRACE("Performing action (%s)\n",debugstr_w(action));
1083 handled = ACTION_HandleStandardAction(package, action, &rc, force);
1085 if (!handled)
1086 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
1088 if (!handled)
1090 WARN("unhandled msi action %s\n",debugstr_w(action));
1091 rc = ERROR_FUNCTION_NOT_CALLED;
1094 return rc;
1097 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
1099 UINT rc = ERROR_SUCCESS;
1100 BOOL handled = FALSE;
1102 TRACE("Performing action (%s)\n",debugstr_w(action));
1104 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1106 if (!handled)
1107 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
1109 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1110 handled = TRUE;
1112 if (!handled)
1114 WARN("unhandled msi action %s\n",debugstr_w(action));
1115 rc = ERROR_FUNCTION_NOT_CALLED;
1118 return rc;
1123 * Actual Action Handlers
1126 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1128 MSIPACKAGE *package = (MSIPACKAGE*)param;
1129 LPCWSTR dir;
1130 LPWSTR full_path;
1131 MSIRECORD *uirow;
1132 MSIFOLDER *folder;
1134 dir = MSI_RecordGetString(row,1);
1135 if (!dir)
1137 ERR("Unable to get folder id\n");
1138 return ERROR_SUCCESS;
1141 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
1142 if (!full_path)
1144 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1145 return ERROR_SUCCESS;
1148 TRACE("Folder is %s\n",debugstr_w(full_path));
1150 /* UI stuff */
1151 uirow = MSI_CreateRecord(1);
1152 MSI_RecordSetStringW(uirow,1,full_path);
1153 ui_actiondata(package,szCreateFolders,uirow);
1154 msiobj_release( &uirow->hdr );
1156 if (folder->State == 0)
1157 create_full_pathW(full_path);
1159 folder->State = 3;
1161 msi_free(full_path);
1162 return ERROR_SUCCESS;
1165 /* FIXME: probably should merge this with the above function */
1166 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1168 UINT rc = ERROR_SUCCESS;
1169 MSIFOLDER *folder;
1170 LPWSTR install_path;
1172 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
1173 if (!install_path)
1174 return ERROR_FUNCTION_FAILED;
1176 /* create the path */
1177 if (folder->State == 0)
1179 create_full_pathW(install_path);
1180 folder->State = 2;
1182 msi_free(install_path);
1184 return rc;
1187 UINT msi_create_component_directories( MSIPACKAGE *package )
1189 MSICOMPONENT *comp;
1191 /* create all the folders required by the components are going to install */
1192 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1194 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1195 continue;
1196 msi_create_directory( package, comp->Directory );
1199 return ERROR_SUCCESS;
1203 * Also we cannot enable/disable components either, so for now I am just going
1204 * to do all the directories for all the components.
1206 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1208 static const WCHAR ExecSeqQuery[] =
1209 {'S','E','L','E','C','T',' ',
1210 '`','D','i','r','e','c','t','o','r','y','_','`',
1211 ' ','F','R','O','M',' ',
1212 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1213 UINT rc;
1214 MSIQUERY *view;
1216 /* create all the empty folders specified in the CreateFolder table */
1217 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1218 if (rc != ERROR_SUCCESS)
1219 return ERROR_SUCCESS;
1221 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1222 msiobj_release(&view->hdr);
1224 msi_create_component_directories( package );
1226 return rc;
1229 static UINT load_component( MSIRECORD *row, LPVOID param )
1231 MSIPACKAGE *package = param;
1232 MSICOMPONENT *comp;
1234 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1235 if (!comp)
1236 return ERROR_FUNCTION_FAILED;
1238 list_add_tail( &package->components, &comp->entry );
1240 /* fill in the data */
1241 comp->Component = msi_dup_record_field( row, 1 );
1243 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1245 comp->ComponentId = msi_dup_record_field( row, 2 );
1246 comp->Directory = msi_dup_record_field( row, 3 );
1247 comp->Attributes = MSI_RecordGetInteger(row,4);
1248 comp->Condition = msi_dup_record_field( row, 5 );
1249 comp->KeyPath = msi_dup_record_field( row, 6 );
1251 comp->Installed = INSTALLSTATE_UNKNOWN;
1252 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1254 return ERROR_SUCCESS;
1257 static UINT load_all_components( MSIPACKAGE *package )
1259 static const WCHAR query[] = {
1260 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1261 '`','C','o','m','p','o','n','e','n','t','`',0 };
1262 MSIQUERY *view;
1263 UINT r;
1265 if (!list_empty(&package->components))
1266 return ERROR_SUCCESS;
1268 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1269 if (r != ERROR_SUCCESS)
1270 return r;
1272 r = MSI_IterateRecords(view, NULL, load_component, package);
1273 msiobj_release(&view->hdr);
1274 return r;
1277 typedef struct {
1278 MSIPACKAGE *package;
1279 MSIFEATURE *feature;
1280 } _ilfs;
1282 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1284 ComponentList *cl;
1286 cl = msi_alloc( sizeof (*cl) );
1287 if ( !cl )
1288 return ERROR_NOT_ENOUGH_MEMORY;
1289 cl->component = comp;
1290 list_add_tail( &feature->Components, &cl->entry );
1292 return ERROR_SUCCESS;
1295 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1297 FeatureList *fl;
1299 fl = msi_alloc( sizeof(*fl) );
1300 if ( !fl )
1301 return ERROR_NOT_ENOUGH_MEMORY;
1302 fl->feature = child;
1303 list_add_tail( &parent->Children, &fl->entry );
1305 return ERROR_SUCCESS;
1308 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1310 _ilfs* ilfs= (_ilfs*)param;
1311 LPCWSTR component;
1312 MSICOMPONENT *comp;
1314 component = MSI_RecordGetString(row,1);
1316 /* check to see if the component is already loaded */
1317 comp = get_loaded_component( ilfs->package, component );
1318 if (!comp)
1320 ERR("unknown component %s\n", debugstr_w(component));
1321 return ERROR_FUNCTION_FAILED;
1324 add_feature_component( ilfs->feature, comp );
1325 comp->Enabled = TRUE;
1327 return ERROR_SUCCESS;
1330 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1332 MSIFEATURE *feature;
1334 if ( !name )
1335 return NULL;
1337 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1339 if ( !lstrcmpW( feature->Feature, name ) )
1340 return feature;
1343 return NULL;
1346 static UINT load_feature(MSIRECORD * row, LPVOID param)
1348 MSIPACKAGE* package = (MSIPACKAGE*)param;
1349 MSIFEATURE* feature;
1350 static const WCHAR Query1[] =
1351 {'S','E','L','E','C','T',' ',
1352 '`','C','o','m','p','o','n','e','n','t','_','`',
1353 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1354 'C','o','m','p','o','n','e','n','t','s','`',' ',
1355 'W','H','E','R','E',' ',
1356 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1357 MSIQUERY * view;
1358 UINT rc;
1359 _ilfs ilfs;
1361 /* fill in the data */
1363 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1364 if (!feature)
1365 return ERROR_NOT_ENOUGH_MEMORY;
1367 list_init( &feature->Children );
1368 list_init( &feature->Components );
1370 feature->Feature = msi_dup_record_field( row, 1 );
1372 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1374 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1375 feature->Title = msi_dup_record_field( row, 3 );
1376 feature->Description = msi_dup_record_field( row, 4 );
1378 if (!MSI_RecordIsNull(row,5))
1379 feature->Display = MSI_RecordGetInteger(row,5);
1381 feature->Level= MSI_RecordGetInteger(row,6);
1382 feature->Directory = msi_dup_record_field( row, 7 );
1383 feature->Attributes = MSI_RecordGetInteger(row,8);
1385 feature->Installed = INSTALLSTATE_UNKNOWN;
1386 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1388 list_add_tail( &package->features, &feature->entry );
1390 /* load feature components */
1392 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1393 if (rc != ERROR_SUCCESS)
1394 return ERROR_SUCCESS;
1396 ilfs.package = package;
1397 ilfs.feature = feature;
1399 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1400 msiobj_release(&view->hdr);
1402 return ERROR_SUCCESS;
1405 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1407 MSIPACKAGE* package = (MSIPACKAGE*)param;
1408 MSIFEATURE *parent, *child;
1410 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1411 if (!child)
1412 return ERROR_FUNCTION_FAILED;
1414 if (!child->Feature_Parent)
1415 return ERROR_SUCCESS;
1417 parent = find_feature_by_name( package, child->Feature_Parent );
1418 if (!parent)
1419 return ERROR_FUNCTION_FAILED;
1421 add_feature_child( parent, child );
1422 return ERROR_SUCCESS;
1425 static UINT load_all_features( MSIPACKAGE *package )
1427 static const WCHAR query[] = {
1428 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1429 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1430 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1431 MSIQUERY *view;
1432 UINT r;
1434 if (!list_empty(&package->features))
1435 return ERROR_SUCCESS;
1437 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1438 if (r != ERROR_SUCCESS)
1439 return r;
1441 r = MSI_IterateRecords( view, NULL, load_feature, package );
1442 if (r != ERROR_SUCCESS)
1443 return r;
1445 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1446 msiobj_release( &view->hdr );
1448 return r;
1451 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1453 if (!p)
1454 return p;
1455 p = strchrW(p, ch);
1456 if (!p)
1457 return p;
1458 *p = 0;
1459 return p+1;
1462 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1464 static const WCHAR query[] = {
1465 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1466 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1467 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1468 MSIQUERY *view = NULL;
1469 MSIRECORD *row = NULL;
1470 UINT r;
1472 TRACE("%s\n", debugstr_w(file->File));
1474 r = MSI_OpenQuery(package->db, &view, query, file->File);
1475 if (r != ERROR_SUCCESS)
1476 goto done;
1478 r = MSI_ViewExecute(view, NULL);
1479 if (r != ERROR_SUCCESS)
1480 goto done;
1482 r = MSI_ViewFetch(view, &row);
1483 if (r != ERROR_SUCCESS)
1484 goto done;
1486 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1487 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1488 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1489 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1490 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1492 done:
1493 if (view) msiobj_release(&view->hdr);
1494 if (row) msiobj_release(&row->hdr);
1495 return r;
1498 static UINT load_file(MSIRECORD *row, LPVOID param)
1500 MSIPACKAGE* package = (MSIPACKAGE*)param;
1501 LPCWSTR component;
1502 MSIFILE *file;
1504 /* fill in the data */
1506 file = msi_alloc_zero( sizeof (MSIFILE) );
1507 if (!file)
1508 return ERROR_NOT_ENOUGH_MEMORY;
1510 file->File = msi_dup_record_field( row, 1 );
1512 component = MSI_RecordGetString( row, 2 );
1513 file->Component = get_loaded_component( package, component );
1515 if (!file->Component)
1517 WARN("Component not found: %s\n", debugstr_w(component));
1518 msi_free(file->File);
1519 msi_free(file);
1520 return ERROR_SUCCESS;
1523 file->FileName = msi_dup_record_field( row, 3 );
1524 reduce_to_longfilename( file->FileName );
1526 file->ShortName = msi_dup_record_field( row, 3 );
1527 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1529 file->FileSize = MSI_RecordGetInteger( row, 4 );
1530 file->Version = msi_dup_record_field( row, 5 );
1531 file->Language = msi_dup_record_field( row, 6 );
1532 file->Attributes = MSI_RecordGetInteger( row, 7 );
1533 file->Sequence = MSI_RecordGetInteger( row, 8 );
1535 file->state = msifs_invalid;
1537 /* if the compressed bits are not set in the file attributes,
1538 * then read the information from the package word count property
1540 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1542 file->IsCompressed = FALSE;
1544 else if (file->Attributes &
1545 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1547 file->IsCompressed = TRUE;
1549 else if (file->Attributes & msidbFileAttributesNoncompressed)
1551 file->IsCompressed = FALSE;
1553 else
1555 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1558 load_file_hash(package, file);
1560 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1562 list_add_tail( &package->files, &file->entry );
1564 return ERROR_SUCCESS;
1567 static UINT load_all_files(MSIPACKAGE *package)
1569 MSIQUERY * view;
1570 UINT rc;
1571 static const WCHAR Query[] =
1572 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1573 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1574 '`','S','e','q','u','e','n','c','e','`', 0};
1576 if (!list_empty(&package->files))
1577 return ERROR_SUCCESS;
1579 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1580 if (rc != ERROR_SUCCESS)
1581 return ERROR_SUCCESS;
1583 rc = MSI_IterateRecords(view, NULL, load_file, package);
1584 msiobj_release(&view->hdr);
1586 return ERROR_SUCCESS;
1589 static UINT load_folder( MSIRECORD *row, LPVOID param )
1591 MSIPACKAGE *package = param;
1592 static const WCHAR szDot[] = { '.',0 };
1593 static WCHAR szEmpty[] = { 0 };
1594 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1595 MSIFOLDER *folder;
1597 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1598 if (!folder)
1599 return ERROR_NOT_ENOUGH_MEMORY;
1601 folder->Directory = msi_dup_record_field( row, 1 );
1603 TRACE("%s\n", debugstr_w(folder->Directory));
1605 p = msi_dup_record_field(row, 3);
1607 /* split src and target dir */
1608 tgt_short = p;
1609 src_short = folder_split_path( p, ':' );
1611 /* split the long and short paths */
1612 tgt_long = folder_split_path( tgt_short, '|' );
1613 src_long = folder_split_path( src_short, '|' );
1615 /* check for no-op dirs */
1616 if (!lstrcmpW(szDot, tgt_short))
1617 tgt_short = szEmpty;
1618 if (!lstrcmpW(szDot, src_short))
1619 src_short = szEmpty;
1621 if (!tgt_long)
1622 tgt_long = tgt_short;
1624 if (!src_short) {
1625 src_short = tgt_short;
1626 src_long = tgt_long;
1629 if (!src_long)
1630 src_long = src_short;
1632 /* FIXME: use the target short path too */
1633 folder->TargetDefault = strdupW(tgt_long);
1634 folder->SourceShortPath = strdupW(src_short);
1635 folder->SourceLongPath = strdupW(src_long);
1636 msi_free(p);
1638 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1639 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1640 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1642 folder->Parent = msi_dup_record_field( row, 2 );
1644 folder->Property = msi_dup_property( package, folder->Directory );
1646 list_add_tail( &package->folders, &folder->entry );
1648 TRACE("returning %p\n", folder);
1650 return ERROR_SUCCESS;
1653 static UINT load_all_folders( MSIPACKAGE *package )
1655 static const WCHAR query[] = {
1656 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1657 '`','D','i','r','e','c','t','o','r','y','`',0 };
1658 MSIQUERY *view;
1659 UINT r;
1661 if (!list_empty(&package->folders))
1662 return ERROR_SUCCESS;
1664 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1665 if (r != ERROR_SUCCESS)
1666 return r;
1668 r = MSI_IterateRecords(view, NULL, load_folder, package);
1669 msiobj_release(&view->hdr);
1670 return r;
1674 * I am not doing any of the costing functionality yet.
1675 * Mostly looking at doing the Component and Feature loading
1677 * The native MSI does A LOT of modification to tables here. Mostly adding
1678 * a lot of temporary columns to the Feature and Component tables.
1680 * note: Native msi also tracks the short filename. But I am only going to
1681 * track the long ones. Also looking at this directory table
1682 * it appears that the directory table does not get the parents
1683 * resolved base on property only based on their entries in the
1684 * directory table.
1686 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1688 static const WCHAR szCosting[] =
1689 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1690 static const WCHAR szZero[] = { '0', 0 };
1692 MSI_SetPropertyW(package, szCosting, szZero);
1693 MSI_SetPropertyW(package, cszRootDrive, c_colon);
1695 load_all_folders( package );
1696 load_all_components( package );
1697 load_all_features( package );
1698 load_all_files( package );
1700 return ERROR_SUCCESS;
1703 static UINT execute_script(MSIPACKAGE *package, UINT script )
1705 UINT i;
1706 UINT rc = ERROR_SUCCESS;
1708 TRACE("Executing Script %i\n",script);
1710 if (!package->script)
1712 ERR("no script!\n");
1713 return ERROR_FUNCTION_FAILED;
1716 for (i = 0; i < package->script->ActionCount[script]; i++)
1718 LPWSTR action;
1719 action = package->script->Actions[script][i];
1720 ui_actionstart(package, action);
1721 TRACE("Executing Action (%s)\n",debugstr_w(action));
1722 rc = ACTION_PerformAction(package, action, script, TRUE);
1723 if (rc != ERROR_SUCCESS)
1724 break;
1726 msi_free_action_script(package, script);
1727 return rc;
1730 static UINT ACTION_FileCost(MSIPACKAGE *package)
1732 return ERROR_SUCCESS;
1735 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1737 MSICOMPONENT *comp;
1738 INSTALLSTATE state;
1739 UINT r;
1741 state = MsiQueryProductStateW(package->ProductCode);
1743 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1745 if (!comp->ComponentId)
1746 continue;
1748 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1749 comp->Installed = INSTALLSTATE_ABSENT;
1750 else
1752 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1753 package->Context, comp->ComponentId,
1754 &comp->Installed);
1755 if (r != ERROR_SUCCESS)
1756 comp->Installed = INSTALLSTATE_ABSENT;
1761 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1763 MSIFEATURE *feature;
1764 INSTALLSTATE state;
1766 state = MsiQueryProductStateW(package->ProductCode);
1768 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1770 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1771 feature->Installed = INSTALLSTATE_ABSENT;
1772 else
1774 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1775 feature->Feature);
1780 static BOOL process_state_property(MSIPACKAGE* package, int level,
1781 LPCWSTR property, INSTALLSTATE state)
1783 static const WCHAR all[]={'A','L','L',0};
1784 static const WCHAR remove[] = {'R','E','M','O','V','E',0};
1785 LPWSTR override;
1786 MSIFEATURE *feature;
1788 override = msi_dup_property( package, property );
1789 if (!override)
1790 return FALSE;
1792 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1794 if (lstrcmpW(property, remove) &&
1795 (feature->Level <= 0 || feature->Level > level))
1796 continue;
1798 if (strcmpiW(override,all)==0)
1799 msi_feature_set_state(package, feature, state);
1800 else
1802 LPWSTR ptr = override;
1803 LPWSTR ptr2 = strchrW(override,',');
1805 while (ptr)
1807 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1808 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1810 msi_feature_set_state(package, feature, state);
1811 break;
1813 if (ptr2)
1815 ptr=ptr2+1;
1816 ptr2 = strchrW(ptr,',');
1818 else
1819 break;
1823 msi_free(override);
1825 return TRUE;
1828 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1830 int level;
1831 static const WCHAR szlevel[] =
1832 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1833 static const WCHAR szAddLocal[] =
1834 {'A','D','D','L','O','C','A','L',0};
1835 static const WCHAR szAddSource[] =
1836 {'A','D','D','S','O','U','R','C','E',0};
1837 static const WCHAR szRemove[] =
1838 {'R','E','M','O','V','E',0};
1839 static const WCHAR szReinstall[] =
1840 {'R','E','I','N','S','T','A','L','L',0};
1841 BOOL override = FALSE;
1842 MSICOMPONENT* component;
1843 MSIFEATURE *feature;
1846 /* I do not know if this is where it should happen.. but */
1848 TRACE("Checking Install Level\n");
1850 level = msi_get_property_int(package, szlevel, 1);
1852 /* ok here is the _real_ rub
1853 * all these activation/deactivation things happen in order and things
1854 * later on the list override things earlier on the list.
1855 * 1) INSTALLLEVEL processing
1856 * 2) ADDLOCAL
1857 * 3) REMOVE
1858 * 4) ADDSOURCE
1859 * 5) ADDDEFAULT
1860 * 6) REINSTALL
1861 * 7) COMPADDLOCAL
1862 * 8) COMPADDSOURCE
1863 * 9) FILEADDLOCAL
1864 * 10) FILEADDSOURCE
1865 * 11) FILEADDDEFAULT
1867 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1868 * REMOVE are the big ones, since we don't handle administrative installs
1869 * yet anyway.
1871 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1872 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1873 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1874 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_LOCAL);
1876 if (!override)
1878 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1880 BOOL feature_state = ((feature->Level > 0) &&
1881 (feature->Level <= level));
1883 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1885 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1886 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1887 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1888 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1889 else
1890 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1894 /* disable child features of unselected parent features */
1895 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1897 FeatureList *fl;
1899 if (feature->Level > 0 && feature->Level <= level)
1900 continue;
1902 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1903 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1906 else
1908 /* set the Preselected Property */
1909 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1910 static const WCHAR szOne[] = { '1', 0 };
1912 MSI_SetPropertyW(package,szPreselected,szOne);
1916 * now we want to enable or disable components base on feature
1919 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1921 ComponentList *cl;
1923 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1924 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1926 if (!feature->Level)
1927 continue;
1929 /* features with components that have compressed files are made local */
1930 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1932 if (cl->component->Enabled &&
1933 cl->component->ForceLocalState &&
1934 feature->Action == INSTALLSTATE_SOURCE)
1936 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1937 break;
1941 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1943 component = cl->component;
1945 if (!component->Enabled)
1946 continue;
1948 switch (feature->Action)
1950 case INSTALLSTATE_ABSENT:
1951 component->anyAbsent = 1;
1952 break;
1953 case INSTALLSTATE_ADVERTISED:
1954 component->hasAdvertiseFeature = 1;
1955 break;
1956 case INSTALLSTATE_SOURCE:
1957 component->hasSourceFeature = 1;
1958 break;
1959 case INSTALLSTATE_LOCAL:
1960 component->hasLocalFeature = 1;
1961 break;
1962 case INSTALLSTATE_DEFAULT:
1963 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1964 component->hasAdvertiseFeature = 1;
1965 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1966 component->hasSourceFeature = 1;
1967 else
1968 component->hasLocalFeature = 1;
1969 break;
1970 default:
1971 break;
1976 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1978 /* if the component isn't enabled, leave it alone */
1979 if (!component->Enabled)
1980 continue;
1982 /* check if it's local or source */
1983 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1984 (component->hasLocalFeature || component->hasSourceFeature))
1986 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1987 !component->ForceLocalState)
1988 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1989 else
1990 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1991 continue;
1994 /* if any feature is local, the component must be local too */
1995 if (component->hasLocalFeature)
1997 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1998 continue;
2001 if (component->hasSourceFeature)
2003 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
2004 continue;
2007 if (component->hasAdvertiseFeature)
2009 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
2010 continue;
2013 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
2014 if (component->anyAbsent)
2015 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
2018 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2020 if (component->Action == INSTALLSTATE_DEFAULT)
2022 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
2023 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
2026 TRACE("Result: Component %s (Installed %i, Action %i)\n",
2027 debugstr_w(component->Component), component->Installed, component->Action);
2031 return ERROR_SUCCESS;
2034 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2036 MSIPACKAGE *package = (MSIPACKAGE*)param;
2037 LPCWSTR name;
2038 LPWSTR path;
2039 MSIFOLDER *f;
2041 name = MSI_RecordGetString(row,1);
2043 f = get_loaded_folder(package, name);
2044 if (!f) return ERROR_SUCCESS;
2046 /* reset the ResolvedTarget */
2047 msi_free(f->ResolvedTarget);
2048 f->ResolvedTarget = NULL;
2050 /* This helper function now does ALL the work */
2051 TRACE("Dir %s ...\n",debugstr_w(name));
2052 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
2053 TRACE("resolves to %s\n",debugstr_w(path));
2054 msi_free(path);
2056 return ERROR_SUCCESS;
2059 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2061 MSIPACKAGE *package = (MSIPACKAGE*)param;
2062 LPCWSTR name;
2063 MSIFEATURE *feature;
2065 name = MSI_RecordGetString( row, 1 );
2067 feature = get_loaded_feature( package, name );
2068 if (!feature)
2069 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
2070 else
2072 LPCWSTR Condition;
2073 Condition = MSI_RecordGetString(row,3);
2075 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
2077 int level = MSI_RecordGetInteger(row,2);
2078 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
2079 feature->Level = level;
2082 return ERROR_SUCCESS;
2085 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
2087 static const WCHAR name_fmt[] =
2088 {'%','u','.','%','u','.','%','u','.','%','u',0};
2089 static const WCHAR name[] = {'\\',0};
2090 VS_FIXEDFILEINFO *lpVer;
2091 WCHAR filever[0x100];
2092 LPVOID version;
2093 DWORD versize;
2094 DWORD handle;
2095 UINT sz;
2097 TRACE("%s\n", debugstr_w(filename));
2099 versize = GetFileVersionInfoSizeW( filename, &handle );
2100 if (!versize)
2101 return NULL;
2103 version = msi_alloc( versize );
2104 GetFileVersionInfoW( filename, 0, versize, version );
2106 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2108 msi_free( version );
2109 return NULL;
2112 sprintfW( filever, name_fmt,
2113 HIWORD(lpVer->dwFileVersionMS),
2114 LOWORD(lpVer->dwFileVersionMS),
2115 HIWORD(lpVer->dwFileVersionLS),
2116 LOWORD(lpVer->dwFileVersionLS));
2118 msi_free( version );
2120 return strdupW( filever );
2123 static UINT msi_check_file_install_states( MSIPACKAGE *package )
2125 LPWSTR file_version;
2126 MSIFILE *file;
2128 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2130 MSICOMPONENT* comp = file->Component;
2131 LPWSTR p;
2133 if (!comp)
2134 continue;
2136 if (file->IsCompressed)
2137 comp->ForceLocalState = TRUE;
2139 /* calculate target */
2140 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
2142 msi_free(file->TargetPath);
2144 TRACE("file %s is named %s\n",
2145 debugstr_w(file->File), debugstr_w(file->FileName));
2147 file->TargetPath = build_directory_name(2, p, file->FileName);
2149 msi_free(p);
2151 TRACE("file %s resolves to %s\n",
2152 debugstr_w(file->File), debugstr_w(file->TargetPath));
2154 /* don't check files of components that aren't installed */
2155 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2156 comp->Installed == INSTALLSTATE_ABSENT)
2158 file->state = msifs_missing; /* assume files are missing */
2159 continue;
2162 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2164 file->state = msifs_missing;
2165 comp->Cost += file->FileSize;
2166 continue;
2169 if (file->Version &&
2170 (file_version = msi_get_disk_file_version( file->TargetPath )))
2172 TRACE("new %s old %s\n", debugstr_w(file->Version),
2173 debugstr_w(file_version));
2174 /* FIXME: seems like a bad way to compare version numbers */
2175 if (lstrcmpiW(file_version, file->Version)<0)
2177 file->state = msifs_overwrite;
2178 comp->Cost += file->FileSize;
2180 else
2181 file->state = msifs_present;
2182 msi_free( file_version );
2184 else
2185 file->state = msifs_present;
2188 return ERROR_SUCCESS;
2192 * A lot is done in this function aside from just the costing.
2193 * The costing needs to be implemented at some point but for now I am going
2194 * to focus on the directory building
2197 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2199 static const WCHAR ExecSeqQuery[] =
2200 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2201 '`','D','i','r','e','c','t','o','r','y','`',0};
2202 static const WCHAR ConditionQuery[] =
2203 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2204 '`','C','o','n','d','i','t','i','o','n','`',0};
2205 static const WCHAR szCosting[] =
2206 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2207 static const WCHAR szlevel[] =
2208 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2209 static const WCHAR szOutOfDiskSpace[] =
2210 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
2211 static const WCHAR szOne[] = { '1', 0 };
2212 static const WCHAR szZero[] = { '0', 0 };
2213 MSICOMPONENT *comp;
2214 UINT rc;
2215 MSIQUERY * view;
2216 LPWSTR level;
2218 TRACE("Building Directory properties\n");
2220 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2221 if (rc == ERROR_SUCCESS)
2223 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2224 package);
2225 msiobj_release(&view->hdr);
2228 /* read components states from the registry */
2229 ACTION_GetComponentInstallStates(package);
2230 ACTION_GetFeatureInstallStates(package);
2232 TRACE("File calculations\n");
2233 msi_check_file_install_states( package );
2235 TRACE("Evaluating Condition Table\n");
2237 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2238 if (rc == ERROR_SUCCESS)
2240 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2241 package);
2242 msiobj_release(&view->hdr);
2245 TRACE("Enabling or Disabling Components\n");
2246 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2248 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2250 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2251 comp->Enabled = FALSE;
2253 else
2254 comp->Enabled = TRUE;
2257 MSI_SetPropertyW(package,szCosting,szOne);
2258 /* set default run level if not set */
2259 level = msi_dup_property( package, szlevel );
2260 if (!level)
2261 MSI_SetPropertyW(package,szlevel, szOne);
2262 msi_free(level);
2264 /* FIXME: check volume disk space */
2265 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2267 return MSI_SetFeatureStates(package);
2270 /* OK this value is "interpreted" and then formatted based on the
2271 first few characters */
2272 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
2273 DWORD *size)
2275 LPSTR data = NULL;
2277 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2279 if (value[1]=='x')
2281 LPWSTR ptr;
2282 CHAR byte[5];
2283 LPWSTR deformated = NULL;
2284 int count;
2286 deformat_string(package, &value[2], &deformated);
2288 /* binary value type */
2289 ptr = deformated;
2290 *type = REG_BINARY;
2291 if (strlenW(ptr)%2)
2292 *size = (strlenW(ptr)/2)+1;
2293 else
2294 *size = strlenW(ptr)/2;
2296 data = msi_alloc(*size);
2298 byte[0] = '0';
2299 byte[1] = 'x';
2300 byte[4] = 0;
2301 count = 0;
2302 /* if uneven pad with a zero in front */
2303 if (strlenW(ptr)%2)
2305 byte[2]= '0';
2306 byte[3]= *ptr;
2307 ptr++;
2308 data[count] = (BYTE)strtol(byte,NULL,0);
2309 count ++;
2310 TRACE("Uneven byte count\n");
2312 while (*ptr)
2314 byte[2]= *ptr;
2315 ptr++;
2316 byte[3]= *ptr;
2317 ptr++;
2318 data[count] = (BYTE)strtol(byte,NULL,0);
2319 count ++;
2321 msi_free(deformated);
2323 TRACE("Data %i bytes(%i)\n",*size,count);
2325 else
2327 LPWSTR deformated;
2328 LPWSTR p;
2329 DWORD d = 0;
2330 deformat_string(package, &value[1], &deformated);
2332 *type=REG_DWORD;
2333 *size = sizeof(DWORD);
2334 data = msi_alloc(*size);
2335 p = deformated;
2336 if (*p == '-')
2337 p++;
2338 while (*p)
2340 if ( (*p < '0') || (*p > '9') )
2341 break;
2342 d *= 10;
2343 d += (*p - '0');
2344 p++;
2346 if (deformated[0] == '-')
2347 d = -d;
2348 *(LPDWORD)data = d;
2349 TRACE("DWORD %i\n",*(LPDWORD)data);
2351 msi_free(deformated);
2354 else
2356 static const WCHAR szMulti[] = {'[','~',']',0};
2357 LPCWSTR ptr;
2358 *type=REG_SZ;
2360 if (value[0]=='#')
2362 if (value[1]=='%')
2364 ptr = &value[2];
2365 *type=REG_EXPAND_SZ;
2367 else
2368 ptr = &value[1];
2370 else
2371 ptr=value;
2373 if (strstrW(value,szMulti))
2374 *type = REG_MULTI_SZ;
2376 /* remove initial delimiter */
2377 if (!strncmpW(value, szMulti, 3))
2378 ptr = value + 3;
2380 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2382 /* add double NULL terminator */
2383 if (*type == REG_MULTI_SZ)
2385 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2386 data = msi_realloc_zero(data, *size);
2389 return data;
2392 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2394 MSIPACKAGE *package = (MSIPACKAGE*)param;
2395 static const WCHAR szHCR[] =
2396 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2397 'R','O','O','T','\\',0};
2398 static const WCHAR szHCU[] =
2399 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2400 'U','S','E','R','\\',0};
2401 static const WCHAR szHLM[] =
2402 {'H','K','E','Y','_','L','O','C','A','L','_',
2403 'M','A','C','H','I','N','E','\\',0};
2404 static const WCHAR szHU[] =
2405 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2407 LPSTR value_data = NULL;
2408 HKEY root_key, hkey;
2409 DWORD type,size;
2410 LPWSTR deformated;
2411 LPCWSTR szRoot, component, name, key, value;
2412 MSICOMPONENT *comp;
2413 MSIRECORD * uirow;
2414 LPWSTR uikey;
2415 INT root;
2416 BOOL check_first = FALSE;
2417 UINT rc;
2419 ui_progress(package,2,0,0,0);
2421 value = NULL;
2422 key = NULL;
2423 uikey = NULL;
2424 name = NULL;
2426 component = MSI_RecordGetString(row, 6);
2427 comp = get_loaded_component(package,component);
2428 if (!comp)
2429 return ERROR_SUCCESS;
2431 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2433 TRACE("Skipping write due to disabled component %s\n",
2434 debugstr_w(component));
2436 comp->Action = comp->Installed;
2438 return ERROR_SUCCESS;
2441 comp->Action = INSTALLSTATE_LOCAL;
2443 name = MSI_RecordGetString(row, 4);
2444 if( MSI_RecordIsNull(row,5) && name )
2446 /* null values can have special meanings */
2447 if (name[0]=='-' && name[1] == 0)
2448 return ERROR_SUCCESS;
2449 else if ((name[0]=='+' && name[1] == 0) ||
2450 (name[0] == '*' && name[1] == 0))
2451 name = NULL;
2452 check_first = TRUE;
2455 root = MSI_RecordGetInteger(row,2);
2456 key = MSI_RecordGetString(row, 3);
2458 /* get the root key */
2459 switch (root)
2461 case -1:
2463 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2464 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2465 if (all_users && all_users[0] == '1')
2467 root_key = HKEY_LOCAL_MACHINE;
2468 szRoot = szHLM;
2470 else
2472 root_key = HKEY_CURRENT_USER;
2473 szRoot = szHCU;
2475 msi_free(all_users);
2477 break;
2478 case 0: root_key = HKEY_CLASSES_ROOT;
2479 szRoot = szHCR;
2480 break;
2481 case 1: root_key = HKEY_CURRENT_USER;
2482 szRoot = szHCU;
2483 break;
2484 case 2: root_key = HKEY_LOCAL_MACHINE;
2485 szRoot = szHLM;
2486 break;
2487 case 3: root_key = HKEY_USERS;
2488 szRoot = szHU;
2489 break;
2490 default:
2491 ERR("Unknown root %i\n",root);
2492 root_key=NULL;
2493 szRoot = NULL;
2494 break;
2496 if (!root_key)
2497 return ERROR_SUCCESS;
2499 deformat_string(package, key , &deformated);
2500 size = strlenW(deformated) + strlenW(szRoot) + 1;
2501 uikey = msi_alloc(size*sizeof(WCHAR));
2502 strcpyW(uikey,szRoot);
2503 strcatW(uikey,deformated);
2505 if (RegCreateKeyW( root_key, deformated, &hkey))
2507 ERR("Could not create key %s\n",debugstr_w(deformated));
2508 msi_free(deformated);
2509 msi_free(uikey);
2510 return ERROR_SUCCESS;
2512 msi_free(deformated);
2514 value = MSI_RecordGetString(row,5);
2515 if (value)
2516 value_data = parse_value(package, value, &type, &size);
2517 else
2519 static const WCHAR szEmpty[] = {0};
2520 value_data = (LPSTR)strdupW(szEmpty);
2521 size = sizeof(szEmpty);
2522 type = REG_SZ;
2525 deformat_string(package, name, &deformated);
2527 if (!check_first)
2529 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2530 debugstr_w(uikey));
2531 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2533 else
2535 DWORD sz = 0;
2536 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2537 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2539 TRACE("value %s of %s checked already exists\n",
2540 debugstr_w(deformated), debugstr_w(uikey));
2542 else
2544 TRACE("Checked and setting value %s of %s\n",
2545 debugstr_w(deformated), debugstr_w(uikey));
2546 if (deformated || size)
2547 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2550 RegCloseKey(hkey);
2552 uirow = MSI_CreateRecord(3);
2553 MSI_RecordSetStringW(uirow,2,deformated);
2554 MSI_RecordSetStringW(uirow,1,uikey);
2556 if (type == REG_SZ)
2557 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2558 else
2559 MSI_RecordSetStringW(uirow,3,value);
2561 ui_actiondata(package,szWriteRegistryValues,uirow);
2562 msiobj_release( &uirow->hdr );
2564 msi_free(value_data);
2565 msi_free(deformated);
2566 msi_free(uikey);
2568 return ERROR_SUCCESS;
2571 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2573 UINT rc;
2574 MSIQUERY * view;
2575 static const WCHAR ExecSeqQuery[] =
2576 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2577 '`','R','e','g','i','s','t','r','y','`',0 };
2579 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2580 if (rc != ERROR_SUCCESS)
2581 return ERROR_SUCCESS;
2583 /* increment progress bar each time action data is sent */
2584 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2586 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2588 msiobj_release(&view->hdr);
2589 return rc;
2592 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2594 package->script->CurrentlyScripting = TRUE;
2596 return ERROR_SUCCESS;
2600 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2602 MSICOMPONENT *comp;
2603 DWORD progress = 0;
2604 DWORD total = 0;
2605 static const WCHAR q1[]=
2606 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2607 '`','R','e','g','i','s','t','r','y','`',0};
2608 UINT rc;
2609 MSIQUERY * view;
2610 MSIFEATURE *feature;
2611 MSIFILE *file;
2613 TRACE("InstallValidate\n");
2615 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2616 if (rc == ERROR_SUCCESS)
2618 MSI_IterateRecords( view, &progress, NULL, package );
2619 msiobj_release( &view->hdr );
2620 total += progress * REG_PROGRESS_VALUE;
2623 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2624 total += COMPONENT_PROGRESS_VALUE;
2626 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2627 total += file->FileSize;
2629 ui_progress(package,0,total,0,0);
2631 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2633 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2634 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2635 feature->ActionRequest);
2638 return ERROR_SUCCESS;
2641 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2643 MSIPACKAGE* package = (MSIPACKAGE*)param;
2644 LPCWSTR cond = NULL;
2645 LPCWSTR message = NULL;
2646 UINT r;
2648 static const WCHAR title[]=
2649 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2651 cond = MSI_RecordGetString(row,1);
2653 r = MSI_EvaluateConditionW(package,cond);
2654 if (r == MSICONDITION_FALSE)
2656 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2658 LPWSTR deformated;
2659 message = MSI_RecordGetString(row,2);
2660 deformat_string(package,message,&deformated);
2661 MessageBoxW(NULL,deformated,title,MB_OK);
2662 msi_free(deformated);
2665 return ERROR_INSTALL_FAILURE;
2668 return ERROR_SUCCESS;
2671 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2673 UINT rc;
2674 MSIQUERY * view = NULL;
2675 static const WCHAR ExecSeqQuery[] =
2676 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2677 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2679 TRACE("Checking launch conditions\n");
2681 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2682 if (rc != ERROR_SUCCESS)
2683 return ERROR_SUCCESS;
2685 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2686 msiobj_release(&view->hdr);
2688 return rc;
2691 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2694 if (!cmp->KeyPath)
2695 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2697 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2699 MSIRECORD * row = 0;
2700 UINT root,len;
2701 LPWSTR deformated,buffer,deformated_name;
2702 LPCWSTR key,name;
2703 static const WCHAR ExecSeqQuery[] =
2704 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2705 '`','R','e','g','i','s','t','r','y','`',' ',
2706 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2707 ' ','=',' ' ,'\'','%','s','\'',0 };
2708 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2709 static const WCHAR fmt2[]=
2710 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2712 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2713 if (!row)
2714 return NULL;
2716 root = MSI_RecordGetInteger(row,2);
2717 key = MSI_RecordGetString(row, 3);
2718 name = MSI_RecordGetString(row, 4);
2719 deformat_string(package, key , &deformated);
2720 deformat_string(package, name, &deformated_name);
2722 len = strlenW(deformated) + 6;
2723 if (deformated_name)
2724 len+=strlenW(deformated_name);
2726 buffer = msi_alloc( len *sizeof(WCHAR));
2728 if (deformated_name)
2729 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2730 else
2731 sprintfW(buffer,fmt,root,deformated);
2733 msi_free(deformated);
2734 msi_free(deformated_name);
2735 msiobj_release(&row->hdr);
2737 return buffer;
2739 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2741 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2742 return NULL;
2744 else
2746 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2748 if (file)
2749 return strdupW( file->TargetPath );
2751 return NULL;
2754 static HKEY openSharedDLLsKey(void)
2756 HKEY hkey=0;
2757 static const WCHAR path[] =
2758 {'S','o','f','t','w','a','r','e','\\',
2759 'M','i','c','r','o','s','o','f','t','\\',
2760 'W','i','n','d','o','w','s','\\',
2761 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2762 'S','h','a','r','e','d','D','L','L','s',0};
2764 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2765 return hkey;
2768 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2770 HKEY hkey;
2771 DWORD count=0;
2772 DWORD type;
2773 DWORD sz = sizeof(count);
2774 DWORD rc;
2776 hkey = openSharedDLLsKey();
2777 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2778 if (rc != ERROR_SUCCESS)
2779 count = 0;
2780 RegCloseKey(hkey);
2781 return count;
2784 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2786 HKEY hkey;
2788 hkey = openSharedDLLsKey();
2789 if (count > 0)
2790 msi_reg_set_val_dword( hkey, path, count );
2791 else
2792 RegDeleteValueW(hkey,path);
2793 RegCloseKey(hkey);
2794 return count;
2798 * Return TRUE if the count should be written out and FALSE if not
2800 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2802 MSIFEATURE *feature;
2803 INT count = 0;
2804 BOOL write = FALSE;
2806 /* only refcount DLLs */
2807 if (comp->KeyPath == NULL ||
2808 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2809 comp->Attributes & msidbComponentAttributesODBCDataSource)
2810 write = FALSE;
2811 else
2813 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2814 write = (count > 0);
2816 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2817 write = TRUE;
2820 /* increment counts */
2821 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2823 ComponentList *cl;
2825 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2826 continue;
2828 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2830 if ( cl->component == comp )
2831 count++;
2835 /* decrement counts */
2836 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2838 ComponentList *cl;
2840 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2841 continue;
2843 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2845 if ( cl->component == comp )
2846 count--;
2850 /* ref count all the files in the component */
2851 if (write)
2853 MSIFILE *file;
2855 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2857 if (file->Component == comp)
2858 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2862 /* add a count for permanent */
2863 if (comp->Attributes & msidbComponentAttributesPermanent)
2864 count ++;
2866 comp->RefCount = count;
2868 if (write)
2869 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2872 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2874 WCHAR squished_pc[GUID_SIZE];
2875 WCHAR squished_cc[GUID_SIZE];
2876 UINT rc;
2877 MSICOMPONENT *comp;
2878 HKEY hkey;
2880 TRACE("\n");
2882 squash_guid(package->ProductCode,squished_pc);
2883 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2885 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2887 MSIRECORD * uirow;
2889 ui_progress(package,2,0,0,0);
2890 if (!comp->ComponentId)
2891 continue;
2893 squash_guid(comp->ComponentId,squished_cc);
2895 msi_free(comp->FullKeypath);
2896 comp->FullKeypath = resolve_keypath( package, comp );
2898 ACTION_RefCountComponent( package, comp );
2900 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2901 debugstr_w(comp->Component),
2902 debugstr_w(squished_cc),
2903 debugstr_w(comp->FullKeypath),
2904 comp->RefCount);
2906 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2907 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2909 if (!comp->FullKeypath)
2910 continue;
2912 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2913 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2914 &hkey, TRUE);
2915 else
2916 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2917 &hkey, TRUE);
2919 if (rc != ERROR_SUCCESS)
2920 continue;
2922 if (comp->Attributes & msidbComponentAttributesPermanent)
2924 static const WCHAR szPermKey[] =
2925 { '0','0','0','0','0','0','0','0','0','0','0','0',
2926 '0','0','0','0','0','0','0','0','0','0','0','0',
2927 '0','0','0','0','0','0','0','0',0 };
2929 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2932 if (comp->Action == INSTALLSTATE_LOCAL)
2933 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2934 else
2936 MSIFILE *file;
2937 MSIRECORD *row;
2938 LPWSTR ptr, ptr2;
2939 WCHAR source[MAX_PATH];
2940 WCHAR base[MAX_PATH];
2941 LPWSTR sourcepath;
2943 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2944 static const WCHAR query[] = {
2945 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2946 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2947 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2948 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2949 '`','D','i','s','k','I','d','`',0};
2951 file = get_loaded_file(package, comp->KeyPath);
2952 if (!file)
2953 continue;
2955 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2956 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2957 ptr2 = strrchrW(source, '\\') + 1;
2958 msiobj_release(&row->hdr);
2960 lstrcpyW(base, package->PackagePath);
2961 ptr = strrchrW(base, '\\');
2962 *(ptr + 1) = '\0';
2964 sourcepath = resolve_file_source(package, file);
2965 ptr = sourcepath + lstrlenW(base);
2966 lstrcpyW(ptr2, ptr);
2967 msi_free(sourcepath);
2969 msi_reg_set_val_str(hkey, squished_pc, source);
2971 RegCloseKey(hkey);
2973 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2975 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2976 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2977 else
2978 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2981 /* UI stuff */
2982 uirow = MSI_CreateRecord(3);
2983 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2984 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2985 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2986 ui_actiondata(package,szProcessComponents,uirow);
2987 msiobj_release( &uirow->hdr );
2990 return ERROR_SUCCESS;
2993 typedef struct {
2994 CLSID clsid;
2995 LPWSTR source;
2997 LPWSTR path;
2998 ITypeLib *ptLib;
2999 } typelib_struct;
3001 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3002 LPWSTR lpszName, LONG_PTR lParam)
3004 TLIBATTR *attr;
3005 typelib_struct *tl_struct = (typelib_struct*) lParam;
3006 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3007 int sz;
3008 HRESULT res;
3010 if (!IS_INTRESOURCE(lpszName))
3012 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3013 return TRUE;
3016 sz = strlenW(tl_struct->source)+4;
3017 sz *= sizeof(WCHAR);
3019 if ((INT_PTR)lpszName == 1)
3020 tl_struct->path = strdupW(tl_struct->source);
3021 else
3023 tl_struct->path = msi_alloc(sz);
3024 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3027 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3028 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3029 if (FAILED(res))
3031 msi_free(tl_struct->path);
3032 tl_struct->path = NULL;
3034 return TRUE;
3037 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3038 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3040 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3041 return FALSE;
3044 msi_free(tl_struct->path);
3045 tl_struct->path = NULL;
3047 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3048 ITypeLib_Release(tl_struct->ptLib);
3050 return TRUE;
3053 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3055 MSIPACKAGE* package = (MSIPACKAGE*)param;
3056 LPCWSTR component;
3057 MSICOMPONENT *comp;
3058 MSIFILE *file;
3059 typelib_struct tl_struct;
3060 ITypeLib *tlib;
3061 HMODULE module;
3062 HRESULT hr;
3064 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3066 component = MSI_RecordGetString(row,3);
3067 comp = get_loaded_component(package,component);
3068 if (!comp)
3069 return ERROR_SUCCESS;
3071 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3073 TRACE("Skipping typelib reg due to disabled component\n");
3075 comp->Action = comp->Installed;
3077 return ERROR_SUCCESS;
3080 comp->Action = INSTALLSTATE_LOCAL;
3082 file = get_loaded_file( package, comp->KeyPath );
3083 if (!file)
3084 return ERROR_SUCCESS;
3086 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3087 if (module)
3089 LPCWSTR guid;
3090 guid = MSI_RecordGetString(row,1);
3091 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
3092 tl_struct.source = strdupW( file->TargetPath );
3093 tl_struct.path = NULL;
3095 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3096 (LONG_PTR)&tl_struct);
3098 if (tl_struct.path)
3100 LPWSTR help = NULL;
3101 LPCWSTR helpid;
3102 HRESULT res;
3104 helpid = MSI_RecordGetString(row,6);
3106 if (helpid)
3107 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3108 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3109 msi_free(help);
3111 if (FAILED(res))
3112 ERR("Failed to register type library %s\n",
3113 debugstr_w(tl_struct.path));
3114 else
3116 ui_actiondata(package,szRegisterTypeLibraries,row);
3118 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3121 ITypeLib_Release(tl_struct.ptLib);
3122 msi_free(tl_struct.path);
3124 else
3125 ERR("Failed to load type library %s\n",
3126 debugstr_w(tl_struct.source));
3128 FreeLibrary(module);
3129 msi_free(tl_struct.source);
3131 else
3133 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3134 if (FAILED(hr))
3136 ERR("Failed to load type library: %08x\n", hr);
3137 return ERROR_FUNCTION_FAILED;
3140 ITypeLib_Release(tlib);
3143 return ERROR_SUCCESS;
3146 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3149 * OK this is a bit confusing.. I am given a _Component key and I believe
3150 * that the file that is being registered as a type library is the "key file
3151 * of that component" which I interpret to mean "The file in the KeyPath of
3152 * that component".
3154 UINT rc;
3155 MSIQUERY * view;
3156 static const WCHAR Query[] =
3157 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3158 '`','T','y','p','e','L','i','b','`',0};
3160 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3161 if (rc != ERROR_SUCCESS)
3162 return ERROR_SUCCESS;
3164 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3165 msiobj_release(&view->hdr);
3166 return rc;
3169 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3171 MSIPACKAGE *package = (MSIPACKAGE*)param;
3172 LPWSTR target_file, target_folder, filename;
3173 LPCWSTR buffer, extension;
3174 MSICOMPONENT *comp;
3175 static const WCHAR szlnk[]={'.','l','n','k',0};
3176 IShellLinkW *sl = NULL;
3177 IPersistFile *pf = NULL;
3178 HRESULT res;
3180 buffer = MSI_RecordGetString(row,4);
3181 comp = get_loaded_component(package,buffer);
3182 if (!comp)
3183 return ERROR_SUCCESS;
3185 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
3187 TRACE("Skipping shortcut creation due to disabled component\n");
3189 comp->Action = comp->Installed;
3191 return ERROR_SUCCESS;
3194 comp->Action = INSTALLSTATE_LOCAL;
3196 ui_actiondata(package,szCreateShortcuts,row);
3198 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3199 &IID_IShellLinkW, (LPVOID *) &sl );
3201 if (FAILED( res ))
3203 ERR("CLSID_ShellLink not available\n");
3204 goto err;
3207 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3208 if (FAILED( res ))
3210 ERR("QueryInterface(IID_IPersistFile) failed\n");
3211 goto err;
3214 buffer = MSI_RecordGetString(row,2);
3215 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
3217 /* may be needed because of a bug somewhere else */
3218 create_full_pathW(target_folder);
3220 filename = msi_dup_record_field( row, 3 );
3221 reduce_to_longfilename(filename);
3223 extension = strchrW(filename,'.');
3224 if (!extension || strcmpiW(extension,szlnk))
3226 int len = strlenW(filename);
3227 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3228 memcpy(filename + len, szlnk, sizeof(szlnk));
3230 target_file = build_directory_name(2, target_folder, filename);
3231 msi_free(target_folder);
3232 msi_free(filename);
3234 buffer = MSI_RecordGetString(row,5);
3235 if (strchrW(buffer,'['))
3237 LPWSTR deformated;
3238 deformat_string(package,buffer,&deformated);
3239 IShellLinkW_SetPath(sl,deformated);
3240 msi_free(deformated);
3242 else
3244 FIXME("poorly handled shortcut format, advertised shortcut\n");
3245 IShellLinkW_SetPath(sl,comp->FullKeypath);
3248 if (!MSI_RecordIsNull(row,6))
3250 LPWSTR deformated;
3251 buffer = MSI_RecordGetString(row,6);
3252 deformat_string(package,buffer,&deformated);
3253 IShellLinkW_SetArguments(sl,deformated);
3254 msi_free(deformated);
3257 if (!MSI_RecordIsNull(row,7))
3259 buffer = MSI_RecordGetString(row,7);
3260 IShellLinkW_SetDescription(sl,buffer);
3263 if (!MSI_RecordIsNull(row,8))
3264 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3266 if (!MSI_RecordIsNull(row,9))
3268 LPWSTR Path;
3269 INT index;
3271 buffer = MSI_RecordGetString(row,9);
3273 Path = build_icon_path(package,buffer);
3274 index = MSI_RecordGetInteger(row,10);
3276 /* no value means 0 */
3277 if (index == MSI_NULL_INTEGER)
3278 index = 0;
3280 IShellLinkW_SetIconLocation(sl,Path,index);
3281 msi_free(Path);
3284 if (!MSI_RecordIsNull(row,11))
3285 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3287 if (!MSI_RecordIsNull(row,12))
3289 LPWSTR Path;
3290 buffer = MSI_RecordGetString(row,12);
3291 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3292 if (Path)
3293 IShellLinkW_SetWorkingDirectory(sl,Path);
3294 msi_free(Path);
3297 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3298 IPersistFile_Save(pf,target_file,FALSE);
3300 msi_free(target_file);
3302 err:
3303 if (pf)
3304 IPersistFile_Release( pf );
3305 if (sl)
3306 IShellLinkW_Release( sl );
3308 return ERROR_SUCCESS;
3311 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3313 UINT rc;
3314 HRESULT res;
3315 MSIQUERY * view;
3316 static const WCHAR Query[] =
3317 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3318 '`','S','h','o','r','t','c','u','t','`',0};
3320 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3321 if (rc != ERROR_SUCCESS)
3322 return ERROR_SUCCESS;
3324 res = CoInitialize( NULL );
3325 if (FAILED (res))
3327 ERR("CoInitialize failed\n");
3328 return ERROR_FUNCTION_FAILED;
3331 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3332 msiobj_release(&view->hdr);
3334 CoUninitialize();
3336 return rc;
3339 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3341 MSIPACKAGE* package = (MSIPACKAGE*)param;
3342 HANDLE the_file;
3343 LPWSTR FilePath;
3344 LPCWSTR FileName;
3345 CHAR buffer[1024];
3346 DWORD sz;
3347 UINT rc;
3348 MSIRECORD *uirow;
3350 FileName = MSI_RecordGetString(row,1);
3351 if (!FileName)
3353 ERR("Unable to get FileName\n");
3354 return ERROR_SUCCESS;
3357 FilePath = build_icon_path(package,FileName);
3359 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3361 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3362 FILE_ATTRIBUTE_NORMAL, NULL);
3364 if (the_file == INVALID_HANDLE_VALUE)
3366 ERR("Unable to create file %s\n",debugstr_w(FilePath));
3367 msi_free(FilePath);
3368 return ERROR_SUCCESS;
3373 DWORD write;
3374 sz = 1024;
3375 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3376 if (rc != ERROR_SUCCESS)
3378 ERR("Failed to get stream\n");
3379 CloseHandle(the_file);
3380 DeleteFileW(FilePath);
3381 break;
3383 WriteFile(the_file,buffer,sz,&write,NULL);
3384 } while (sz == 1024);
3386 msi_free(FilePath);
3388 CloseHandle(the_file);
3390 uirow = MSI_CreateRecord(1);
3391 MSI_RecordSetStringW(uirow,1,FileName);
3392 ui_actiondata(package,szPublishProduct,uirow);
3393 msiobj_release( &uirow->hdr );
3395 return ERROR_SUCCESS;
3398 static UINT msi_publish_icons(MSIPACKAGE *package)
3400 UINT r;
3401 MSIQUERY *view;
3403 static const WCHAR query[]= {
3404 'S','E','L','E','C','T',' ','*',' ',
3405 'F','R','O','M',' ','`','I','c','o','n','`',0};
3407 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3408 if (r == ERROR_SUCCESS)
3410 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3411 msiobj_release(&view->hdr);
3414 return ERROR_SUCCESS;
3417 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3419 UINT r;
3420 HKEY source;
3421 LPWSTR buffer;
3422 MSIMEDIADISK *disk;
3423 MSISOURCELISTINFO *info;
3425 static const WCHAR szEmpty[] = {0};
3426 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
3428 r = RegCreateKeyW(hkey, szSourceList, &source);
3429 if (r != ERROR_SUCCESS)
3430 return r;
3432 RegCloseKey(source);
3434 buffer = strrchrW(package->PackagePath, '\\') + 1;
3435 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3436 package->Context, MSICODE_PRODUCT,
3437 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3438 if (r != ERROR_SUCCESS)
3439 return r;
3441 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3442 package->Context, MSICODE_PRODUCT,
3443 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3444 if (r != ERROR_SUCCESS)
3445 return r;
3447 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3448 package->Context, MSICODE_PRODUCT,
3449 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3450 if (r != ERROR_SUCCESS)
3451 return r;
3453 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3455 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3456 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3457 info->options, info->value);
3458 else
3459 MsiSourceListSetInfoW(package->ProductCode, NULL,
3460 info->context, info->options,
3461 info->property, info->value);
3464 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3466 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3467 disk->context, disk->options,
3468 disk->disk_id, disk->volume_label, disk->disk_prompt);
3471 return ERROR_SUCCESS;
3474 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3476 MSIHANDLE hdb, suminfo;
3477 WCHAR guids[MAX_PATH];
3478 WCHAR packcode[SQUISH_GUID_SIZE];
3479 LPWSTR buffer;
3480 LPWSTR ptr;
3481 DWORD langid;
3482 DWORD size;
3483 UINT r;
3485 static const WCHAR szProductLanguage[] =
3486 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3487 static const WCHAR szARPProductIcon[] =
3488 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3489 static const WCHAR szProductVersion[] =
3490 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3491 static const WCHAR szAssignment[] =
3492 {'A','s','s','i','g','n','m','e','n','t',0};
3493 static const WCHAR szAdvertiseFlags[] =
3494 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3495 static const WCHAR szClients[] =
3496 {'C','l','i','e','n','t','s',0};
3497 static const WCHAR szColon[] = {':',0};
3499 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3500 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3501 msi_free(buffer);
3503 langid = msi_get_property_int(package, szProductLanguage, 0);
3504 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3506 ptr = strrchrW(package->PackagePath, '\\' ) + 1;
3507 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGENAMEW, ptr);
3509 /* FIXME */
3510 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3512 buffer = msi_dup_property(package, szARPProductIcon);
3513 if (buffer)
3515 LPWSTR path = build_icon_path(package,buffer);
3516 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3517 msi_free(path);
3518 msi_free(buffer);
3521 buffer = msi_dup_property(package, szProductVersion);
3522 if (buffer)
3524 DWORD verdword = msi_version_str_to_dword(buffer);
3525 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3526 msi_free(buffer);
3529 msi_reg_set_val_dword(hkey, szAssignment, 0);
3530 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3531 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3532 msi_reg_set_val_str(hkey, szClients, szColon);
3534 hdb = alloc_msihandle(&package->db->hdr);
3535 if (!hdb)
3536 return ERROR_NOT_ENOUGH_MEMORY;
3538 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3539 MsiCloseHandle(hdb);
3540 if (r != ERROR_SUCCESS)
3541 goto done;
3543 size = MAX_PATH;
3544 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3545 NULL, guids, &size);
3546 if (r != ERROR_SUCCESS)
3547 goto done;
3549 ptr = strchrW(guids, ';');
3550 if (ptr) *ptr = 0;
3551 squash_guid(guids, packcode);
3552 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3554 done:
3555 MsiCloseHandle(suminfo);
3556 return ERROR_SUCCESS;
3559 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3561 UINT r;
3562 HKEY hkey;
3563 LPWSTR upgrade;
3564 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3566 static const WCHAR szUpgradeCode[] =
3567 {'U','p','g','r','a','d','e','C','o','d','e',0};
3569 upgrade = msi_dup_property(package, szUpgradeCode);
3570 if (!upgrade)
3571 return ERROR_SUCCESS;
3573 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3575 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3576 if (r != ERROR_SUCCESS)
3577 goto done;
3579 else
3581 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3582 if (r != ERROR_SUCCESS)
3583 goto done;
3586 squash_guid(package->ProductCode, squashed_pc);
3587 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3589 RegCloseKey(hkey);
3591 done:
3592 msi_free(upgrade);
3593 return r;
3596 static BOOL msi_check_publish(MSIPACKAGE *package)
3598 MSIFEATURE *feature;
3600 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3602 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3603 return TRUE;
3606 return FALSE;
3609 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3611 MSIFEATURE *feature;
3613 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3615 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3616 return FALSE;
3619 return TRUE;
3622 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3624 WCHAR patch_squashed[GUID_SIZE];
3625 HKEY patches;
3626 LONG res;
3627 UINT r = ERROR_FUNCTION_FAILED;
3629 static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
3631 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3632 &patches, NULL);
3633 if (res != ERROR_SUCCESS)
3634 return ERROR_FUNCTION_FAILED;
3636 squash_guid(package->patch->patchcode, patch_squashed);
3638 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3639 (const BYTE *)patch_squashed,
3640 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3641 if (res != ERROR_SUCCESS)
3642 goto done;
3644 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3645 (const BYTE *)package->patch->transforms,
3646 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3647 if (res == ERROR_SUCCESS)
3648 r = ERROR_SUCCESS;
3650 done:
3651 RegCloseKey(patches);
3652 return r;
3656 * 99% of the work done here is only done for
3657 * advertised installs. However this is where the
3658 * Icon table is processed and written out
3659 * so that is what I am going to do here.
3661 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3663 UINT rc;
3664 HKEY hukey=0;
3665 HKEY hudkey=0;
3667 /* FIXME: also need to publish if the product is in advertise mode */
3668 if (!msi_check_publish(package))
3669 return ERROR_SUCCESS;
3671 rc = MSIREG_OpenProductKey(package->ProductCode, package->Context,
3672 &hukey, TRUE);
3673 if (rc != ERROR_SUCCESS)
3674 goto end;
3676 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3677 NULL, &hudkey, TRUE);
3678 if (rc != ERROR_SUCCESS)
3679 goto end;
3681 rc = msi_publish_upgrade_code(package);
3682 if (rc != ERROR_SUCCESS)
3683 goto end;
3685 if (package->patch)
3687 rc = msi_publish_patch(package, hukey, hudkey);
3688 if (rc != ERROR_SUCCESS)
3689 goto end;
3692 rc = msi_publish_product_properties(package, hukey);
3693 if (rc != ERROR_SUCCESS)
3694 goto end;
3696 rc = msi_publish_sourcelist(package, hukey);
3697 if (rc != ERROR_SUCCESS)
3698 goto end;
3700 rc = msi_publish_icons(package);
3702 end:
3703 RegCloseKey(hukey);
3704 RegCloseKey(hudkey);
3706 return rc;
3709 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3711 MSIPACKAGE *package = (MSIPACKAGE*)param;
3712 LPCWSTR component, section, key, value, identifier, dirproperty;
3713 LPWSTR deformated_section, deformated_key, deformated_value;
3714 LPWSTR folder, filename, fullname = NULL;
3715 LPCWSTR filenameptr;
3716 MSIRECORD * uirow;
3717 INT action;
3718 MSICOMPONENT *comp;
3719 static const WCHAR szWindowsFolder[] =
3720 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3722 component = MSI_RecordGetString(row, 8);
3723 comp = get_loaded_component(package,component);
3725 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3727 TRACE("Skipping ini file due to disabled component %s\n",
3728 debugstr_w(component));
3730 comp->Action = comp->Installed;
3732 return ERROR_SUCCESS;
3735 comp->Action = INSTALLSTATE_LOCAL;
3737 identifier = MSI_RecordGetString(row,1);
3738 dirproperty = MSI_RecordGetString(row,3);
3739 section = MSI_RecordGetString(row,4);
3740 key = MSI_RecordGetString(row,5);
3741 value = MSI_RecordGetString(row,6);
3742 action = MSI_RecordGetInteger(row,7);
3744 deformat_string(package,section,&deformated_section);
3745 deformat_string(package,key,&deformated_key);
3746 deformat_string(package,value,&deformated_value);
3748 filename = msi_dup_record_field(row, 2);
3749 if (filename && (filenameptr = strchrW(filename, '|')))
3750 filenameptr++;
3751 else
3752 filenameptr = filename;
3754 if (dirproperty)
3756 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3757 if (!folder)
3758 folder = msi_dup_property( package, dirproperty );
3760 else
3761 folder = msi_dup_property( package, szWindowsFolder );
3763 if (!folder)
3765 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3766 goto cleanup;
3769 fullname = build_directory_name(2, folder, filenameptr);
3771 if (action == 0)
3773 TRACE("Adding value %s to section %s in %s\n",
3774 debugstr_w(deformated_key), debugstr_w(deformated_section),
3775 debugstr_w(fullname));
3776 WritePrivateProfileStringW(deformated_section, deformated_key,
3777 deformated_value, fullname);
3779 else if (action == 1)
3781 WCHAR returned[10];
3782 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3783 returned, 10, fullname);
3784 if (returned[0] == 0)
3786 TRACE("Adding value %s to section %s in %s\n",
3787 debugstr_w(deformated_key), debugstr_w(deformated_section),
3788 debugstr_w(fullname));
3790 WritePrivateProfileStringW(deformated_section, deformated_key,
3791 deformated_value, fullname);
3794 else if (action == 3)
3795 FIXME("Append to existing section not yet implemented\n");
3797 uirow = MSI_CreateRecord(4);
3798 MSI_RecordSetStringW(uirow,1,identifier);
3799 MSI_RecordSetStringW(uirow,2,deformated_section);
3800 MSI_RecordSetStringW(uirow,3,deformated_key);
3801 MSI_RecordSetStringW(uirow,4,deformated_value);
3802 ui_actiondata(package,szWriteIniValues,uirow);
3803 msiobj_release( &uirow->hdr );
3805 cleanup:
3806 msi_free(filename);
3807 msi_free(fullname);
3808 msi_free(folder);
3809 msi_free(deformated_key);
3810 msi_free(deformated_value);
3811 msi_free(deformated_section);
3812 return ERROR_SUCCESS;
3815 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3817 UINT rc;
3818 MSIQUERY * view;
3819 static const WCHAR ExecSeqQuery[] =
3820 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3821 '`','I','n','i','F','i','l','e','`',0};
3823 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3824 if (rc != ERROR_SUCCESS)
3826 TRACE("no IniFile table\n");
3827 return ERROR_SUCCESS;
3830 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3831 msiobj_release(&view->hdr);
3832 return rc;
3835 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3837 MSIPACKAGE *package = (MSIPACKAGE*)param;
3838 LPCWSTR filename;
3839 LPWSTR FullName;
3840 MSIFILE *file;
3841 DWORD len;
3842 static const WCHAR ExeStr[] =
3843 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3844 static const WCHAR close[] = {'\"',0};
3845 STARTUPINFOW si;
3846 PROCESS_INFORMATION info;
3847 BOOL brc;
3848 MSIRECORD *uirow;
3849 LPWSTR uipath, p;
3851 memset(&si,0,sizeof(STARTUPINFOW));
3853 filename = MSI_RecordGetString(row,1);
3854 file = get_loaded_file( package, filename );
3856 if (!file)
3858 ERR("Unable to find file id %s\n",debugstr_w(filename));
3859 return ERROR_SUCCESS;
3862 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3864 FullName = msi_alloc(len*sizeof(WCHAR));
3865 strcpyW(FullName,ExeStr);
3866 strcatW( FullName, file->TargetPath );
3867 strcatW(FullName,close);
3869 TRACE("Registering %s\n",debugstr_w(FullName));
3870 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3871 &si, &info);
3873 if (brc)
3875 CloseHandle(info.hThread);
3876 msi_dialog_check_messages(info.hProcess);
3877 CloseHandle(info.hProcess);
3880 msi_free(FullName);
3882 /* the UI chunk */
3883 uirow = MSI_CreateRecord( 2 );
3884 uipath = strdupW( file->TargetPath );
3885 p = strrchrW(uipath,'\\');
3886 if (p)
3887 p[0]=0;
3888 MSI_RecordSetStringW( uirow, 1, &p[1] );
3889 MSI_RecordSetStringW( uirow, 2, uipath);
3890 ui_actiondata( package, szSelfRegModules, uirow);
3891 msiobj_release( &uirow->hdr );
3892 msi_free( uipath );
3893 /* FIXME: call ui_progress? */
3895 return ERROR_SUCCESS;
3898 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3900 UINT rc;
3901 MSIQUERY * view;
3902 static const WCHAR ExecSeqQuery[] =
3903 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3904 '`','S','e','l','f','R','e','g','`',0};
3906 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3907 if (rc != ERROR_SUCCESS)
3909 TRACE("no SelfReg table\n");
3910 return ERROR_SUCCESS;
3913 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3914 msiobj_release(&view->hdr);
3916 return ERROR_SUCCESS;
3919 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3921 MSIFEATURE *feature;
3922 UINT rc;
3923 HKEY hkey;
3924 HKEY userdata = NULL;
3926 if (!msi_check_publish(package))
3927 return ERROR_SUCCESS;
3929 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3930 &hkey, TRUE);
3931 if (rc != ERROR_SUCCESS)
3932 goto end;
3934 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3935 &userdata, TRUE);
3936 if (rc != ERROR_SUCCESS)
3937 goto end;
3939 /* here the guids are base 85 encoded */
3940 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3942 ComponentList *cl;
3943 LPWSTR data = NULL;
3944 GUID clsid;
3945 INT size;
3946 BOOL absent = FALSE;
3947 MSIRECORD *uirow;
3949 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3950 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3951 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3952 absent = TRUE;
3954 size = 1;
3955 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3957 size += 21;
3959 if (feature->Feature_Parent)
3960 size += strlenW( feature->Feature_Parent )+2;
3962 data = msi_alloc(size * sizeof(WCHAR));
3964 data[0] = 0;
3965 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3967 MSICOMPONENT* component = cl->component;
3968 WCHAR buf[21];
3970 buf[0] = 0;
3971 if (component->ComponentId)
3973 TRACE("From %s\n",debugstr_w(component->ComponentId));
3974 CLSIDFromString(component->ComponentId, &clsid);
3975 encode_base85_guid(&clsid,buf);
3976 TRACE("to %s\n",debugstr_w(buf));
3977 strcatW(data,buf);
3981 if (feature->Feature_Parent)
3983 static const WCHAR sep[] = {'\2',0};
3984 strcatW(data,sep);
3985 strcatW(data,feature->Feature_Parent);
3988 msi_reg_set_val_str( userdata, feature->Feature, data );
3989 msi_free(data);
3991 size = 0;
3992 if (feature->Feature_Parent)
3993 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3994 if (!absent)
3996 static const WCHAR emptyW[] = {0};
3997 size += sizeof(WCHAR);
3998 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3999 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
4001 else
4003 size += 2*sizeof(WCHAR);
4004 data = msi_alloc(size);
4005 data[0] = 0x6;
4006 data[1] = 0;
4007 if (feature->Feature_Parent)
4008 strcpyW( &data[1], feature->Feature_Parent );
4009 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4010 (LPBYTE)data,size);
4011 msi_free(data);
4014 /* the UI chunk */
4015 uirow = MSI_CreateRecord( 1 );
4016 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4017 ui_actiondata( package, szPublishFeatures, uirow);
4018 msiobj_release( &uirow->hdr );
4019 /* FIXME: call ui_progress? */
4022 end:
4023 RegCloseKey(hkey);
4024 RegCloseKey(userdata);
4025 return rc;
4028 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4030 UINT r;
4031 HKEY hkey;
4033 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4035 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4036 &hkey, FALSE);
4037 if (r == ERROR_SUCCESS)
4039 RegDeleteValueW(hkey, feature->Feature);
4040 RegCloseKey(hkey);
4043 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4044 &hkey, FALSE);
4045 if (r == ERROR_SUCCESS)
4047 RegDeleteValueW(hkey, feature->Feature);
4048 RegCloseKey(hkey);
4051 return ERROR_SUCCESS;
4054 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4056 MSIFEATURE *feature;
4058 if (!msi_check_unpublish(package))
4059 return ERROR_SUCCESS;
4061 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4063 msi_unpublish_feature(package, feature);
4066 return ERROR_SUCCESS;
4069 static UINT msi_get_local_package_name( LPWSTR path )
4071 static const WCHAR szInstaller[] = {
4072 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4073 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
4074 DWORD time, len, i;
4075 HANDLE handle;
4077 time = GetTickCount();
4078 GetWindowsDirectoryW( path, MAX_PATH );
4079 lstrcatW( path, szInstaller );
4080 CreateDirectoryW( path, NULL );
4082 len = lstrlenW(path);
4083 for (i=0; i<0x10000; i++)
4085 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
4086 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
4087 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
4088 if (handle != INVALID_HANDLE_VALUE)
4090 CloseHandle(handle);
4091 break;
4093 if (GetLastError() != ERROR_FILE_EXISTS &&
4094 GetLastError() != ERROR_SHARING_VIOLATION)
4095 return ERROR_FUNCTION_FAILED;
4098 return ERROR_SUCCESS;
4101 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4103 WCHAR packagefile[MAX_PATH];
4104 UINT r;
4106 r = msi_get_local_package_name( packagefile );
4107 if (r != ERROR_SUCCESS)
4108 return r;
4110 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4112 r = CopyFileW( package->db->path, packagefile, FALSE);
4114 if (!r)
4116 ERR("Unable to copy package (%s -> %s) (error %d)\n",
4117 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
4118 return ERROR_FUNCTION_FAILED;
4121 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
4123 return ERROR_SUCCESS;
4126 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4128 LPWSTR prop, val, key;
4129 SYSTEMTIME systime;
4130 DWORD size, langid;
4131 WCHAR date[9];
4132 LPWSTR buffer;
4134 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4135 static const WCHAR szWindowsInstaller[] =
4136 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4137 static const WCHAR modpath_fmt[] =
4138 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4139 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4140 static const WCHAR szModifyPath[] =
4141 {'M','o','d','i','f','y','P','a','t','h',0};
4142 static const WCHAR szUninstallString[] =
4143 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4144 static const WCHAR szEstimatedSize[] =
4145 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4146 static const WCHAR szProductLanguage[] =
4147 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4148 static const WCHAR szProductVersion[] =
4149 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4150 static const WCHAR szProductName[] =
4151 {'P','r','o','d','u','c','t','N','a','m','e',0};
4152 static const WCHAR szDisplayName[] =
4153 {'D','i','s','p','l','a','y','N','a','m','e',0};
4154 static const WCHAR szDisplayVersion[] =
4155 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4156 static const WCHAR szManufacturer[] =
4157 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4159 static const LPCSTR propval[] = {
4160 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4161 "ARPCONTACT", "Contact",
4162 "ARPCOMMENTS", "Comments",
4163 "ProductName", "DisplayName",
4164 "ProductVersion", "DisplayVersion",
4165 "ARPHELPLINK", "HelpLink",
4166 "ARPHELPTELEPHONE", "HelpTelephone",
4167 "ARPINSTALLLOCATION", "InstallLocation",
4168 "SourceDir", "InstallSource",
4169 "Manufacturer", "Publisher",
4170 "ARPREADME", "Readme",
4171 "ARPSIZE", "Size",
4172 "ARPURLINFOABOUT", "URLInfoAbout",
4173 "ARPURLUPDATEINFO", "URLUpdateInfo",
4174 NULL,
4176 const LPCSTR *p = propval;
4178 while (*p)
4180 prop = strdupAtoW(*p++);
4181 key = strdupAtoW(*p++);
4182 val = msi_dup_property(package, prop);
4183 msi_reg_set_val_str(hkey, key, val);
4184 msi_free(val);
4185 msi_free(key);
4186 msi_free(prop);
4189 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4191 size = deformat_string(package, modpath_fmt, &buffer);
4192 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4193 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4194 msi_free(buffer);
4196 /* FIXME: Write real Estimated Size when we have it */
4197 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4199 buffer = msi_dup_property(package, szProductName);
4200 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4201 msi_free(buffer);
4203 buffer = msi_dup_property(package, cszSourceDir);
4204 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4205 msi_free(buffer);
4207 buffer = msi_dup_property(package, szManufacturer);
4208 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4209 msi_free(buffer);
4211 GetLocalTime(&systime);
4212 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4213 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4215 langid = msi_get_property_int(package, szProductLanguage, 0);
4216 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4218 buffer = msi_dup_property(package, szProductVersion);
4219 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4220 if (buffer)
4222 DWORD verdword = msi_version_str_to_dword(buffer);
4224 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4225 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4226 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4227 msi_free(buffer);
4230 return ERROR_SUCCESS;
4233 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4235 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4236 LPWSTR upgrade_code;
4237 HKEY hkey, props;
4238 HKEY upgrade;
4239 UINT rc;
4241 static const WCHAR szUpgradeCode[] = {
4242 'U','p','g','r','a','d','e','C','o','d','e',0};
4244 /* FIXME: also need to publish if the product is in advertise mode */
4245 if (!msi_check_publish(package))
4246 return ERROR_SUCCESS;
4248 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
4249 if (rc != ERROR_SUCCESS)
4250 return rc;
4252 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4253 NULL, &props, TRUE);
4254 if (rc != ERROR_SUCCESS)
4255 goto done;
4257 msi_make_package_local(package, props);
4259 rc = msi_publish_install_properties(package, hkey);
4260 if (rc != ERROR_SUCCESS)
4261 goto done;
4263 rc = msi_publish_install_properties(package, props);
4264 if (rc != ERROR_SUCCESS)
4265 goto done;
4267 upgrade_code = msi_dup_property(package, szUpgradeCode);
4268 if (upgrade_code)
4270 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4271 squash_guid(package->ProductCode, squashed_pc);
4272 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4273 RegCloseKey(upgrade);
4274 msi_free(upgrade_code);
4277 done:
4278 RegCloseKey(hkey);
4280 return ERROR_SUCCESS;
4283 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4285 return execute_script(package,INSTALL_SCRIPT);
4288 static UINT msi_unpublish_product(MSIPACKAGE *package)
4290 LPWSTR upgrade;
4291 LPWSTR remove = NULL;
4292 LPWSTR *features = NULL;
4293 BOOL full_uninstall = TRUE;
4294 MSIFEATURE *feature;
4296 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4297 static const WCHAR szAll[] = {'A','L','L',0};
4298 static const WCHAR szUpgradeCode[] =
4299 {'U','p','g','r','a','d','e','C','o','d','e',0};
4301 remove = msi_dup_property(package, szRemove);
4302 if (!remove)
4303 return ERROR_SUCCESS;
4305 features = msi_split_string(remove, ',');
4306 if (!features)
4308 msi_free(remove);
4309 ERR("REMOVE feature list is empty!\n");
4310 return ERROR_FUNCTION_FAILED;
4313 if (!lstrcmpW(features[0], szAll))
4314 full_uninstall = TRUE;
4315 else
4317 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4319 if (feature->Action != INSTALLSTATE_ABSENT)
4320 full_uninstall = FALSE;
4324 if (!full_uninstall)
4325 goto done;
4327 MSIREG_DeleteProductKey(package->ProductCode);
4328 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4329 MSIREG_DeleteUninstallKey(package->ProductCode);
4331 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4333 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4334 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4336 else
4338 MSIREG_DeleteUserProductKey(package->ProductCode);
4339 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4342 upgrade = msi_dup_property(package, szUpgradeCode);
4343 if (upgrade)
4345 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4346 msi_free(upgrade);
4349 done:
4350 msi_free(remove);
4351 msi_free(features);
4352 return ERROR_SUCCESS;
4355 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4357 UINT rc;
4359 rc = msi_unpublish_product(package);
4360 if (rc != ERROR_SUCCESS)
4361 return rc;
4363 /* turn off scheduling */
4364 package->script->CurrentlyScripting= FALSE;
4366 /* first do the same as an InstallExecute */
4367 rc = ACTION_InstallExecute(package);
4368 if (rc != ERROR_SUCCESS)
4369 return rc;
4371 /* then handle Commit Actions */
4372 rc = execute_script(package,COMMIT_SCRIPT);
4374 return rc;
4377 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4379 static const WCHAR RunOnce[] = {
4380 'S','o','f','t','w','a','r','e','\\',
4381 'M','i','c','r','o','s','o','f','t','\\',
4382 'W','i','n','d','o','w','s','\\',
4383 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4384 'R','u','n','O','n','c','e',0};
4385 static const WCHAR InstallRunOnce[] = {
4386 'S','o','f','t','w','a','r','e','\\',
4387 'M','i','c','r','o','s','o','f','t','\\',
4388 'W','i','n','d','o','w','s','\\',
4389 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4390 'I','n','s','t','a','l','l','e','r','\\',
4391 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
4393 static const WCHAR msiexec_fmt[] = {
4394 '%','s',
4395 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4396 '\"','%','s','\"',0};
4397 static const WCHAR install_fmt[] = {
4398 '/','I',' ','\"','%','s','\"',' ',
4399 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4400 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
4401 WCHAR buffer[256], sysdir[MAX_PATH];
4402 HKEY hkey;
4403 WCHAR squished_pc[100];
4405 squash_guid(package->ProductCode,squished_pc);
4407 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
4408 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
4409 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4410 squished_pc);
4412 msi_reg_set_val_str( hkey, squished_pc, buffer );
4413 RegCloseKey(hkey);
4415 TRACE("Reboot command %s\n",debugstr_w(buffer));
4417 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
4418 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
4420 msi_reg_set_val_str( hkey, squished_pc, buffer );
4421 RegCloseKey(hkey);
4423 return ERROR_INSTALL_SUSPEND;
4426 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
4428 DWORD attrib;
4429 UINT rc;
4432 * We are currently doing what should be done here in the top level Install
4433 * however for Administrative and uninstalls this step will be needed
4435 if (!package->PackagePath)
4436 return ERROR_SUCCESS;
4438 msi_set_sourcedir_props(package, TRUE);
4440 attrib = GetFileAttributesW(package->db->path);
4441 if (attrib == INVALID_FILE_ATTRIBUTES)
4443 LPWSTR prompt;
4444 LPWSTR msg;
4445 DWORD size = 0;
4447 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4448 package->Context, MSICODE_PRODUCT,
4449 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4450 if (rc == ERROR_MORE_DATA)
4452 prompt = msi_alloc(size * sizeof(WCHAR));
4453 MsiSourceListGetInfoW(package->ProductCode, NULL,
4454 package->Context, MSICODE_PRODUCT,
4455 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4457 else
4458 prompt = strdupW(package->db->path);
4460 msg = generate_error_string(package,1302,1,prompt);
4461 while(attrib == INVALID_FILE_ATTRIBUTES)
4463 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4464 if (rc == IDCANCEL)
4466 rc = ERROR_INSTALL_USEREXIT;
4467 break;
4469 attrib = GetFileAttributesW(package->db->path);
4471 msi_free(prompt);
4472 rc = ERROR_SUCCESS;
4474 else
4475 return ERROR_SUCCESS;
4477 return rc;
4480 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4482 HKEY hkey=0;
4483 LPWSTR buffer;
4484 LPWSTR productid;
4485 UINT rc,i;
4487 static const WCHAR szPropKeys[][80] =
4489 {'P','r','o','d','u','c','t','I','D',0},
4490 {'U','S','E','R','N','A','M','E',0},
4491 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4492 {0},
4495 static const WCHAR szRegKeys[][80] =
4497 {'P','r','o','d','u','c','t','I','D',0},
4498 {'R','e','g','O','w','n','e','r',0},
4499 {'R','e','g','C','o','m','p','a','n','y',0},
4500 {0},
4503 if (msi_check_unpublish(package))
4505 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4506 return ERROR_SUCCESS;
4509 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
4510 if (!productid)
4511 return ERROR_SUCCESS;
4513 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4514 NULL, &hkey, TRUE);
4515 if (rc != ERROR_SUCCESS)
4516 goto end;
4518 for( i = 0; szPropKeys[i][0]; i++ )
4520 buffer = msi_dup_property( package, szPropKeys[i] );
4521 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
4522 msi_free( buffer );
4525 end:
4526 msi_free(productid);
4527 RegCloseKey(hkey);
4529 /* FIXME: call ui_actiondata */
4531 return rc;
4535 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4537 UINT rc;
4539 package->script->InWhatSequence |= SEQUENCE_EXEC;
4540 rc = ACTION_ProcessExecSequence(package,FALSE);
4541 return rc;
4545 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4547 MSIPACKAGE *package = (MSIPACKAGE*)param;
4548 LPCWSTR compgroupid=NULL;
4549 LPCWSTR feature=NULL;
4550 LPCWSTR text = NULL;
4551 LPCWSTR qualifier = NULL;
4552 LPCWSTR component = NULL;
4553 LPWSTR advertise = NULL;
4554 LPWSTR output = NULL;
4555 HKEY hkey;
4556 UINT rc = ERROR_SUCCESS;
4557 MSICOMPONENT *comp;
4558 DWORD sz = 0;
4559 MSIRECORD *uirow;
4561 component = MSI_RecordGetString(rec,3);
4562 comp = get_loaded_component(package,component);
4564 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4565 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4566 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
4568 TRACE("Skipping: Component %s not scheduled for install\n",
4569 debugstr_w(component));
4571 return ERROR_SUCCESS;
4574 compgroupid = MSI_RecordGetString(rec,1);
4575 qualifier = MSI_RecordGetString(rec,2);
4577 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4578 if (rc != ERROR_SUCCESS)
4579 goto end;
4581 text = MSI_RecordGetString(rec,4);
4582 feature = MSI_RecordGetString(rec,5);
4584 advertise = create_component_advertise_string(package, comp, feature);
4586 sz = strlenW(advertise);
4588 if (text)
4589 sz += lstrlenW(text);
4591 sz+=3;
4592 sz *= sizeof(WCHAR);
4594 output = msi_alloc_zero(sz);
4595 strcpyW(output,advertise);
4596 msi_free(advertise);
4598 if (text)
4599 strcatW(output,text);
4601 msi_reg_set_val_multi_str( hkey, qualifier, output );
4603 end:
4604 RegCloseKey(hkey);
4605 msi_free(output);
4607 /* the UI chunk */
4608 uirow = MSI_CreateRecord( 2 );
4609 MSI_RecordSetStringW( uirow, 1, compgroupid );
4610 MSI_RecordSetStringW( uirow, 2, qualifier);
4611 ui_actiondata( package, szPublishComponents, uirow);
4612 msiobj_release( &uirow->hdr );
4613 /* FIXME: call ui_progress? */
4615 return rc;
4619 * At present I am ignorning the advertised components part of this and only
4620 * focusing on the qualified component sets
4622 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4624 UINT rc;
4625 MSIQUERY * view;
4626 static const WCHAR ExecSeqQuery[] =
4627 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4628 '`','P','u','b','l','i','s','h',
4629 'C','o','m','p','o','n','e','n','t','`',0};
4631 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4632 if (rc != ERROR_SUCCESS)
4633 return ERROR_SUCCESS;
4635 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4636 msiobj_release(&view->hdr);
4638 return rc;
4641 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4643 MSIPACKAGE *package = (MSIPACKAGE*)param;
4644 MSIRECORD *row;
4645 MSIFILE *file;
4646 SC_HANDLE hscm, service = NULL;
4647 LPCWSTR comp, depends, pass;
4648 LPWSTR name = NULL, disp = NULL;
4649 LPCWSTR load_order, serv_name, key;
4650 DWORD serv_type, start_type;
4651 DWORD err_control;
4653 static const WCHAR query[] =
4654 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4655 '`','C','o','m','p','o','n','e','n','t','`',' ',
4656 'W','H','E','R','E',' ',
4657 '`','C','o','m','p','o','n','e','n','t','`',' ',
4658 '=','\'','%','s','\'',0};
4660 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4661 if (!hscm)
4663 ERR("Failed to open the SC Manager!\n");
4664 goto done;
4667 start_type = MSI_RecordGetInteger(rec, 5);
4668 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4669 goto done;
4671 depends = MSI_RecordGetString(rec, 8);
4672 if (depends && *depends)
4673 FIXME("Dependency list unhandled!\n");
4675 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4676 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
4677 serv_type = MSI_RecordGetInteger(rec, 4);
4678 err_control = MSI_RecordGetInteger(rec, 6);
4679 load_order = MSI_RecordGetString(rec, 7);
4680 serv_name = MSI_RecordGetString(rec, 9);
4681 pass = MSI_RecordGetString(rec, 10);
4682 comp = MSI_RecordGetString(rec, 12);
4684 /* fetch the service path */
4685 row = MSI_QueryGetRecord(package->db, query, comp);
4686 if (!row)
4688 ERR("Control query failed!\n");
4689 goto done;
4692 key = MSI_RecordGetString(row, 6);
4694 file = get_loaded_file(package, key);
4695 msiobj_release(&row->hdr);
4696 if (!file)
4698 ERR("Failed to load the service file\n");
4699 goto done;
4702 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4703 start_type, err_control, file->TargetPath,
4704 load_order, NULL, NULL, serv_name, pass);
4705 if (!service)
4707 if (GetLastError() != ERROR_SERVICE_EXISTS)
4708 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4711 done:
4712 CloseServiceHandle(service);
4713 CloseServiceHandle(hscm);
4714 msi_free(name);
4715 msi_free(disp);
4717 return ERROR_SUCCESS;
4720 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4722 UINT rc;
4723 MSIQUERY * view;
4724 static const WCHAR ExecSeqQuery[] =
4725 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4726 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4728 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4729 if (rc != ERROR_SUCCESS)
4730 return ERROR_SUCCESS;
4732 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4733 msiobj_release(&view->hdr);
4735 return rc;
4738 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4739 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
4741 LPCWSTR *vector, *temp_vector;
4742 LPWSTR p, q;
4743 DWORD sep_len;
4745 static const WCHAR separator[] = {'[','~',']',0};
4747 *numargs = 0;
4748 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4750 if (!args)
4751 return NULL;
4753 vector = msi_alloc(sizeof(LPWSTR));
4754 if (!vector)
4755 return NULL;
4757 p = args;
4760 (*numargs)++;
4761 vector[*numargs - 1] = p;
4763 if ((q = strstrW(p, separator)))
4765 *q = '\0';
4767 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4768 if (!temp_vector)
4770 msi_free(vector);
4771 return NULL;
4773 vector = temp_vector;
4775 p = q + sep_len;
4777 } while (q);
4779 return vector;
4782 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4784 MSIPACKAGE *package = (MSIPACKAGE *)param;
4785 MSICOMPONENT *comp;
4786 SC_HANDLE scm, service = NULL;
4787 LPCWSTR name, *vector = NULL;
4788 LPWSTR args;
4789 DWORD event, numargs;
4790 UINT r = ERROR_FUNCTION_FAILED;
4792 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4793 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4794 return ERROR_SUCCESS;
4796 name = MSI_RecordGetString(rec, 2);
4797 event = MSI_RecordGetInteger(rec, 3);
4798 args = strdupW(MSI_RecordGetString(rec, 4));
4800 if (!(event & msidbServiceControlEventStart))
4801 return ERROR_SUCCESS;
4803 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4804 if (!scm)
4806 ERR("Failed to open the service control manager\n");
4807 goto done;
4810 service = OpenServiceW(scm, name, SERVICE_START);
4811 if (!service)
4813 ERR("Failed to open service %s\n", debugstr_w(name));
4814 goto done;
4817 vector = msi_service_args_to_vector(args, &numargs);
4819 if (!StartServiceW(service, numargs, vector))
4821 ERR("Failed to start service %s\n", debugstr_w(name));
4822 goto done;
4825 r = ERROR_SUCCESS;
4827 done:
4828 CloseServiceHandle(service);
4829 CloseServiceHandle(scm);
4831 msi_free(args);
4832 msi_free(vector);
4833 return r;
4836 static UINT ACTION_StartServices( MSIPACKAGE *package )
4838 UINT rc;
4839 MSIQUERY *view;
4841 static const WCHAR query[] = {
4842 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4843 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4845 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4846 if (rc != ERROR_SUCCESS)
4847 return ERROR_SUCCESS;
4849 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4850 msiobj_release(&view->hdr);
4852 return rc;
4855 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4857 DWORD i, needed, count;
4858 ENUM_SERVICE_STATUSW *dependencies;
4859 SERVICE_STATUS ss;
4860 SC_HANDLE depserv;
4862 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4863 0, &needed, &count))
4864 return TRUE;
4866 if (GetLastError() != ERROR_MORE_DATA)
4867 return FALSE;
4869 dependencies = msi_alloc(needed);
4870 if (!dependencies)
4871 return FALSE;
4873 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4874 needed, &needed, &count))
4875 goto error;
4877 for (i = 0; i < count; i++)
4879 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4880 SERVICE_STOP | SERVICE_QUERY_STATUS);
4881 if (!depserv)
4882 goto error;
4884 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4885 goto error;
4888 return TRUE;
4890 error:
4891 msi_free(dependencies);
4892 return FALSE;
4895 static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4897 MSIPACKAGE *package = (MSIPACKAGE *)param;
4898 MSICOMPONENT *comp;
4899 SERVICE_STATUS status;
4900 SERVICE_STATUS_PROCESS ssp;
4901 SC_HANDLE scm = NULL, service = NULL;
4902 LPWSTR name, args;
4903 DWORD event, needed;
4905 event = MSI_RecordGetInteger(rec, 3);
4906 if (!(event & msidbServiceControlEventStop))
4907 return ERROR_SUCCESS;
4909 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4910 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4911 return ERROR_SUCCESS;
4913 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4914 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4915 args = strdupW(MSI_RecordGetString(rec, 4));
4917 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4918 if (!scm)
4920 WARN("Failed to open the SCM: %d\n", GetLastError());
4921 goto done;
4924 service = OpenServiceW(scm, name,
4925 SERVICE_STOP |
4926 SERVICE_QUERY_STATUS |
4927 SERVICE_ENUMERATE_DEPENDENTS);
4928 if (!service)
4930 WARN("Failed to open service (%s): %d\n",
4931 debugstr_w(name), GetLastError());
4932 goto done;
4935 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4936 sizeof(SERVICE_STATUS_PROCESS), &needed))
4938 WARN("Failed to query service status (%s): %d\n",
4939 debugstr_w(name), GetLastError());
4940 goto done;
4943 if (ssp.dwCurrentState == SERVICE_STOPPED)
4944 goto done;
4946 stop_service_dependents(scm, service);
4948 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
4949 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4951 done:
4952 CloseServiceHandle(service);
4953 CloseServiceHandle(scm);
4954 msi_free(name);
4955 msi_free(args);
4957 return ERROR_SUCCESS;
4960 static UINT ACTION_StopServices( MSIPACKAGE *package )
4962 UINT rc;
4963 MSIQUERY *view;
4965 static const WCHAR query[] = {
4966 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4967 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4969 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4970 if (rc != ERROR_SUCCESS)
4971 return ERROR_SUCCESS;
4973 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4974 msiobj_release(&view->hdr);
4976 return rc;
4979 static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4981 MSIFILE *file;
4983 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4985 if (!lstrcmpW(file->File, filename))
4986 return file;
4989 return NULL;
4992 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4994 MSIPACKAGE *package = (MSIPACKAGE*)param;
4995 LPWSTR driver, driver_path, ptr;
4996 WCHAR outpath[MAX_PATH];
4997 MSIFILE *driver_file, *setup_file;
4998 LPCWSTR desc;
4999 DWORD len, usage;
5000 UINT r = ERROR_SUCCESS;
5002 static const WCHAR driver_fmt[] = {
5003 'D','r','i','v','e','r','=','%','s',0};
5004 static const WCHAR setup_fmt[] = {
5005 'S','e','t','u','p','=','%','s',0};
5006 static const WCHAR usage_fmt[] = {
5007 'F','i','l','e','U','s','a','g','e','=','1',0};
5009 desc = MSI_RecordGetString(rec, 3);
5011 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5012 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5014 if (!driver_file || !setup_file)
5016 ERR("ODBC Driver entry not found!\n");
5017 return ERROR_FUNCTION_FAILED;
5020 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
5021 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
5022 lstrlenW(usage_fmt) + 1;
5023 driver = msi_alloc(len * sizeof(WCHAR));
5024 if (!driver)
5025 return ERROR_OUTOFMEMORY;
5027 ptr = driver;
5028 lstrcpyW(ptr, desc);
5029 ptr += lstrlenW(ptr) + 1;
5031 sprintfW(ptr, driver_fmt, driver_file->FileName);
5032 ptr += lstrlenW(ptr) + 1;
5034 sprintfW(ptr, setup_fmt, setup_file->FileName);
5035 ptr += lstrlenW(ptr) + 1;
5037 lstrcpyW(ptr, usage_fmt);
5038 ptr += lstrlenW(ptr) + 1;
5039 *ptr = '\0';
5041 driver_path = strdupW(driver_file->TargetPath);
5042 ptr = strrchrW(driver_path, '\\');
5043 if (ptr) *ptr = '\0';
5045 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5046 NULL, ODBC_INSTALL_COMPLETE, &usage))
5048 ERR("Failed to install SQL driver!\n");
5049 r = ERROR_FUNCTION_FAILED;
5052 msi_free(driver);
5053 msi_free(driver_path);
5055 return r;
5058 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5060 MSIPACKAGE *package = (MSIPACKAGE*)param;
5061 LPWSTR translator, translator_path, ptr;
5062 WCHAR outpath[MAX_PATH];
5063 MSIFILE *translator_file, *setup_file;
5064 LPCWSTR desc;
5065 DWORD len, usage;
5066 UINT r = ERROR_SUCCESS;
5068 static const WCHAR translator_fmt[] = {
5069 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5070 static const WCHAR setup_fmt[] = {
5071 'S','e','t','u','p','=','%','s',0};
5073 desc = MSI_RecordGetString(rec, 3);
5075 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5076 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5078 if (!translator_file || !setup_file)
5080 ERR("ODBC Translator entry not found!\n");
5081 return ERROR_FUNCTION_FAILED;
5084 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5085 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5086 translator = msi_alloc(len * sizeof(WCHAR));
5087 if (!translator)
5088 return ERROR_OUTOFMEMORY;
5090 ptr = translator;
5091 lstrcpyW(ptr, desc);
5092 ptr += lstrlenW(ptr) + 1;
5094 sprintfW(ptr, translator_fmt, translator_file->FileName);
5095 ptr += lstrlenW(ptr) + 1;
5097 sprintfW(ptr, setup_fmt, setup_file->FileName);
5098 ptr += lstrlenW(ptr) + 1;
5099 *ptr = '\0';
5101 translator_path = strdupW(translator_file->TargetPath);
5102 ptr = strrchrW(translator_path, '\\');
5103 if (ptr) *ptr = '\0';
5105 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5106 NULL, ODBC_INSTALL_COMPLETE, &usage))
5108 ERR("Failed to install SQL translator!\n");
5109 r = ERROR_FUNCTION_FAILED;
5112 msi_free(translator);
5113 msi_free(translator_path);
5115 return r;
5118 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5120 LPWSTR attrs;
5121 LPCWSTR desc, driver;
5122 WORD request = ODBC_ADD_SYS_DSN;
5123 INT registration;
5124 DWORD len;
5125 UINT r = ERROR_SUCCESS;
5127 static const WCHAR attrs_fmt[] = {
5128 'D','S','N','=','%','s',0 };
5130 desc = MSI_RecordGetString(rec, 3);
5131 driver = MSI_RecordGetString(rec, 4);
5132 registration = MSI_RecordGetInteger(rec, 5);
5134 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5135 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5137 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5138 attrs = msi_alloc(len * sizeof(WCHAR));
5139 if (!attrs)
5140 return ERROR_OUTOFMEMORY;
5142 sprintfW(attrs, attrs_fmt, desc);
5143 attrs[len - 1] = '\0';
5145 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5147 ERR("Failed to install SQL data source!\n");
5148 r = ERROR_FUNCTION_FAILED;
5151 msi_free(attrs);
5153 return r;
5156 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5158 UINT rc;
5159 MSIQUERY *view;
5161 static const WCHAR driver_query[] = {
5162 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5163 'O','D','B','C','D','r','i','v','e','r',0 };
5165 static const WCHAR translator_query[] = {
5166 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5167 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5169 static const WCHAR source_query[] = {
5170 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5171 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5173 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
5174 if (rc != ERROR_SUCCESS)
5175 return ERROR_SUCCESS;
5177 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5178 msiobj_release(&view->hdr);
5180 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5181 if (rc != ERROR_SUCCESS)
5182 return ERROR_SUCCESS;
5184 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5185 msiobj_release(&view->hdr);
5187 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5188 if (rc != ERROR_SUCCESS)
5189 return ERROR_SUCCESS;
5191 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5192 msiobj_release(&view->hdr);
5194 return rc;
5197 #define ENV_ACT_SETALWAYS 0x1
5198 #define ENV_ACT_SETABSENT 0x2
5199 #define ENV_ACT_REMOVE 0x4
5200 #define ENV_ACT_REMOVEMATCH 0x8
5202 #define ENV_MOD_MACHINE 0x20000000
5203 #define ENV_MOD_APPEND 0x40000000
5204 #define ENV_MOD_PREFIX 0x80000000
5205 #define ENV_MOD_MASK 0xC0000000
5207 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5209 static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
5211 LPCWSTR cptr = *name;
5212 LPCWSTR ptr = *value;
5214 static const WCHAR prefix[] = {'[','~',']',0};
5215 static const int prefix_len = 3;
5217 *flags = 0;
5218 while (*cptr)
5220 if (*cptr == '=')
5221 *flags |= ENV_ACT_SETALWAYS;
5222 else if (*cptr == '+')
5223 *flags |= ENV_ACT_SETABSENT;
5224 else if (*cptr == '-')
5225 *flags |= ENV_ACT_REMOVE;
5226 else if (*cptr == '!')
5227 *flags |= ENV_ACT_REMOVEMATCH;
5228 else if (*cptr == '*')
5229 *flags |= ENV_MOD_MACHINE;
5230 else
5231 break;
5233 cptr++;
5234 (*name)++;
5237 if (!*cptr)
5239 ERR("Missing environment variable\n");
5240 return ERROR_FUNCTION_FAILED;
5243 if (!strncmpW(ptr, prefix, prefix_len))
5245 *flags |= ENV_MOD_APPEND;
5246 *value += lstrlenW(prefix);
5248 else if (lstrlenW(*value) >= prefix_len)
5250 ptr += lstrlenW(ptr) - prefix_len;
5251 if (!lstrcmpW(ptr, prefix))
5253 *flags |= ENV_MOD_PREFIX;
5254 /* the "[~]" will be removed by deformat_string */;
5258 if (!*flags ||
5259 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5260 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5261 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5262 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5264 ERR("Invalid flags: %08x\n", *flags);
5265 return ERROR_FUNCTION_FAILED;
5268 return ERROR_SUCCESS;
5271 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5273 MSIPACKAGE *package = param;
5274 LPCWSTR name, value;
5275 LPWSTR data = NULL, newval = NULL;
5276 LPWSTR deformatted = NULL, ptr;
5277 DWORD flags, type, size;
5278 LONG res;
5279 HKEY env = NULL, root;
5280 LPCWSTR environment;
5282 static const WCHAR user_env[] =
5283 {'E','n','v','i','r','o','n','m','e','n','t',0};
5284 static const WCHAR machine_env[] =
5285 {'S','y','s','t','e','m','\\',
5286 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5287 'C','o','n','t','r','o','l','\\',
5288 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5289 'E','n','v','i','r','o','n','m','e','n','t',0};
5290 static const WCHAR semicolon[] = {';',0};
5292 name = MSI_RecordGetString(rec, 2);
5293 value = MSI_RecordGetString(rec, 3);
5295 res = env_set_flags(&name, &value, &flags);
5296 if (res != ERROR_SUCCESS)
5297 goto done;
5299 deformat_string(package, value, &deformatted);
5300 if (!deformatted)
5302 res = ERROR_OUTOFMEMORY;
5303 goto done;
5306 value = deformatted;
5308 if (flags & ENV_MOD_MACHINE)
5310 environment = machine_env;
5311 root = HKEY_LOCAL_MACHINE;
5313 else
5315 environment = user_env;
5316 root = HKEY_CURRENT_USER;
5319 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5320 KEY_ALL_ACCESS, NULL, &env, NULL);
5321 if (res != ERROR_SUCCESS)
5322 goto done;
5324 if (flags & ENV_ACT_REMOVE)
5325 FIXME("Not removing environment variable on uninstall!\n");
5327 size = 0;
5328 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5329 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
5330 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
5331 goto done;
5333 if (res != ERROR_FILE_NOT_FOUND)
5335 if (flags & ENV_ACT_SETABSENT)
5337 res = ERROR_SUCCESS;
5338 goto done;
5341 data = msi_alloc(size);
5342 if (!data)
5344 RegCloseKey(env);
5345 return ERROR_OUTOFMEMORY;
5348 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5349 if (res != ERROR_SUCCESS)
5350 goto done;
5352 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5354 res = RegDeleteKeyW(env, name);
5355 goto done;
5358 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5359 newval = msi_alloc(size);
5360 ptr = newval;
5361 if (!newval)
5363 res = ERROR_OUTOFMEMORY;
5364 goto done;
5367 if (!(flags & ENV_MOD_MASK))
5368 lstrcpyW(newval, value);
5369 else
5371 if (flags & ENV_MOD_PREFIX)
5373 lstrcpyW(newval, value);
5374 lstrcatW(newval, semicolon);
5375 ptr = newval + lstrlenW(value) + 1;
5378 lstrcpyW(ptr, data);
5380 if (flags & ENV_MOD_APPEND)
5382 lstrcatW(newval, semicolon);
5383 lstrcatW(newval, value);
5387 else
5389 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
5390 newval = msi_alloc(size);
5391 if (!newval)
5393 res = ERROR_OUTOFMEMORY;
5394 goto done;
5397 lstrcpyW(newval, value);
5400 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5401 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5403 done:
5404 if (env) RegCloseKey(env);
5405 msi_free(deformatted);
5406 msi_free(data);
5407 msi_free(newval);
5408 return res;
5411 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5413 UINT rc;
5414 MSIQUERY * view;
5415 static const WCHAR ExecSeqQuery[] =
5416 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5417 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5418 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5419 if (rc != ERROR_SUCCESS)
5420 return ERROR_SUCCESS;
5422 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5423 msiobj_release(&view->hdr);
5425 return rc;
5428 #define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5430 typedef struct
5432 struct list entry;
5433 LPWSTR sourcename;
5434 LPWSTR destname;
5435 LPWSTR source;
5436 LPWSTR dest;
5437 } FILE_LIST;
5439 static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5441 BOOL ret;
5443 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5444 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5446 WARN("Source or dest is directory, not moving\n");
5447 return FALSE;
5450 if (options == msidbMoveFileOptionsMove)
5452 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5453 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5454 if (!ret)
5456 WARN("MoveFile failed: %d\n", GetLastError());
5457 return FALSE;
5460 else
5462 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5463 ret = CopyFileW(source, dest, FALSE);
5464 if (!ret)
5466 WARN("CopyFile failed: %d\n", GetLastError());
5467 return FALSE;
5471 return TRUE;
5474 static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5476 LPWSTR path, ptr;
5477 DWORD dirlen, pathlen;
5479 ptr = strrchrW(wildcard, '\\');
5480 dirlen = ptr - wildcard + 1;
5482 pathlen = dirlen + lstrlenW(filename) + 1;
5483 path = msi_alloc(pathlen * sizeof(WCHAR));
5485 lstrcpynW(path, wildcard, dirlen + 1);
5486 lstrcatW(path, filename);
5488 return path;
5491 static void free_file_entry(FILE_LIST *file)
5493 msi_free(file->source);
5494 msi_free(file->dest);
5495 msi_free(file);
5498 static void free_list(FILE_LIST *list)
5500 while (!list_empty(&list->entry))
5502 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5504 list_remove(&file->entry);
5505 free_file_entry(file);
5509 static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5511 FILE_LIST *new, *file;
5512 LPWSTR ptr, filename;
5513 DWORD size;
5515 new = msi_alloc_zero(sizeof(FILE_LIST));
5516 if (!new)
5517 return FALSE;
5519 new->source = strdupW(source);
5520 ptr = strrchrW(dest, '\\') + 1;
5521 filename = strrchrW(new->source, '\\') + 1;
5523 new->sourcename = filename;
5525 if (*ptr)
5526 new->destname = ptr;
5527 else
5528 new->destname = new->sourcename;
5530 size = (ptr - dest) + lstrlenW(filename) + 1;
5531 new->dest = msi_alloc(size * sizeof(WCHAR));
5532 if (!new->dest)
5534 free_file_entry(new);
5535 return FALSE;
5538 lstrcpynW(new->dest, dest, ptr - dest + 1);
5539 lstrcatW(new->dest, filename);
5541 if (list_empty(&files->entry))
5543 list_add_head(&files->entry, &new->entry);
5544 return TRUE;
5547 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5549 if (lstrcmpW(source, file->source) < 0)
5551 list_add_before(&file->entry, &new->entry);
5552 return TRUE;
5556 list_add_after(&file->entry, &new->entry);
5557 return TRUE;
5560 static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5562 WIN32_FIND_DATAW wfd;
5563 HANDLE hfile;
5564 LPWSTR path;
5565 BOOL res;
5566 FILE_LIST files, *file;
5567 DWORD size;
5569 hfile = FindFirstFileW(source, &wfd);
5570 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5572 list_init(&files.entry);
5574 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5576 if (is_dot_dir(wfd.cFileName)) continue;
5578 path = wildcard_to_file(source, wfd.cFileName);
5579 if (!path)
5581 res = FALSE;
5582 goto done;
5585 add_wildcard(&files, path, dest);
5586 msi_free(path);
5589 /* no files match the wildcard */
5590 if (list_empty(&files.entry))
5591 goto done;
5593 /* only the first wildcard match gets renamed to dest */
5594 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5595 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5596 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5597 if (!file->dest)
5599 res = FALSE;
5600 goto done;
5603 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5605 while (!list_empty(&files.entry))
5607 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5609 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5611 list_remove(&file->entry);
5612 free_file_entry(file);
5615 res = TRUE;
5617 done:
5618 free_list(&files);
5619 FindClose(hfile);
5620 return res;
5623 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5625 MSIPACKAGE *package = param;
5626 MSICOMPONENT *comp;
5627 LPCWSTR sourcename;
5628 LPWSTR destname = NULL;
5629 LPWSTR sourcedir = NULL, destdir = NULL;
5630 LPWSTR source = NULL, dest = NULL;
5631 int options;
5632 DWORD size;
5633 BOOL ret, wildcards;
5635 static const WCHAR backslash[] = {'\\',0};
5637 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5638 if (!comp || !comp->Enabled ||
5639 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5641 TRACE("Component not set for install, not moving file\n");
5642 return ERROR_SUCCESS;
5645 sourcename = MSI_RecordGetString(rec, 3);
5646 options = MSI_RecordGetInteger(rec, 7);
5648 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5649 if (!sourcedir)
5650 goto done;
5652 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5653 if (!destdir)
5654 goto done;
5656 if (!sourcename)
5658 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5659 goto done;
5661 source = strdupW(sourcedir);
5662 if (!source)
5663 goto done;
5665 else
5667 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5668 source = msi_alloc(size * sizeof(WCHAR));
5669 if (!source)
5670 goto done;
5672 lstrcpyW(source, sourcedir);
5673 if (source[lstrlenW(source) - 1] != '\\')
5674 lstrcatW(source, backslash);
5675 lstrcatW(source, sourcename);
5678 wildcards = strchrW(source, '*') || strchrW(source, '?');
5680 if (MSI_RecordIsNull(rec, 4))
5682 if (!wildcards)
5684 destname = strdupW(sourcename);
5685 if (!destname)
5686 goto done;
5689 else
5691 destname = strdupW(MSI_RecordGetString(rec, 4));
5692 if (destname)
5693 reduce_to_longfilename(destname);
5696 size = 0;
5697 if (destname)
5698 size = lstrlenW(destname);
5700 size += lstrlenW(destdir) + 2;
5701 dest = msi_alloc(size * sizeof(WCHAR));
5702 if (!dest)
5703 goto done;
5705 lstrcpyW(dest, destdir);
5706 if (dest[lstrlenW(dest) - 1] != '\\')
5707 lstrcatW(dest, backslash);
5709 if (destname)
5710 lstrcatW(dest, destname);
5712 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5714 ret = CreateDirectoryW(destdir, NULL);
5715 if (!ret)
5717 WARN("CreateDirectory failed: %d\n", GetLastError());
5718 return ERROR_SUCCESS;
5722 if (!wildcards)
5723 msi_move_file(source, dest, options);
5724 else
5725 move_files_wildcard(source, dest, options);
5727 done:
5728 msi_free(sourcedir);
5729 msi_free(destdir);
5730 msi_free(destname);
5731 msi_free(source);
5732 msi_free(dest);
5734 return ERROR_SUCCESS;
5737 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5739 UINT rc;
5740 MSIQUERY *view;
5742 static const WCHAR ExecSeqQuery[] =
5743 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5744 '`','M','o','v','e','F','i','l','e','`',0};
5746 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5747 if (rc != ERROR_SUCCESS)
5748 return ERROR_SUCCESS;
5750 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5751 msiobj_release(&view->hdr);
5753 return rc;
5756 typedef struct tagMSIASSEMBLY
5758 struct list entry;
5759 MSICOMPONENT *component;
5760 MSIFEATURE *feature;
5761 MSIFILE *file;
5762 LPWSTR manifest;
5763 LPWSTR application;
5764 DWORD attributes;
5765 BOOL installed;
5766 } MSIASSEMBLY;
5768 static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5769 DWORD dwReserved);
5770 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5771 LPVOID pvReserved, HMODULE *phModDll);
5773 static BOOL init_functionpointers(void)
5775 HRESULT hr;
5776 HMODULE hfusion;
5777 HMODULE hmscoree;
5779 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5781 hmscoree = LoadLibraryA("mscoree.dll");
5782 if (!hmscoree)
5784 WARN("mscoree.dll not available\n");
5785 return FALSE;
5788 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5789 if (!pLoadLibraryShim)
5791 WARN("LoadLibraryShim not available\n");
5792 FreeLibrary(hmscoree);
5793 return FALSE;
5796 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5797 if (FAILED(hr))
5799 WARN("fusion.dll not available\n");
5800 FreeLibrary(hmscoree);
5801 return FALSE;
5804 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5806 FreeLibrary(hmscoree);
5807 return TRUE;
5810 static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5811 LPWSTR path)
5813 IAssemblyCache *cache;
5814 HRESULT hr;
5815 UINT r = ERROR_FUNCTION_FAILED;
5817 TRACE("installing assembly: %s\n", debugstr_w(path));
5819 if (assembly->feature)
5820 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
5822 if (assembly->manifest)
5823 FIXME("Manifest unhandled\n");
5825 if (assembly->application)
5827 FIXME("Assembly should be privately installed\n");
5828 return ERROR_SUCCESS;
5831 if (assembly->attributes == msidbAssemblyAttributesWin32)
5833 FIXME("Win32 assemblies not handled\n");
5834 return ERROR_SUCCESS;
5837 hr = pCreateAssemblyCache(&cache, 0);
5838 if (FAILED(hr))
5839 goto done;
5841 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5842 if (FAILED(hr))
5843 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5845 r = ERROR_SUCCESS;
5847 done:
5848 IAssemblyCache_Release(cache);
5849 return r;
5852 typedef struct tagASSEMBLY_LIST
5854 MSIPACKAGE *package;
5855 IAssemblyCache *cache;
5856 struct list *assemblies;
5857 } ASSEMBLY_LIST;
5859 typedef struct tagASSEMBLY_NAME
5861 LPWSTR name;
5862 LPWSTR version;
5863 LPWSTR culture;
5864 LPWSTR pubkeytoken;
5865 } ASSEMBLY_NAME;
5867 static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5869 ASSEMBLY_NAME *asmname = (ASSEMBLY_NAME *)param;
5870 LPCWSTR name = MSI_RecordGetString(rec, 2);
5871 LPWSTR val = msi_dup_record_field(rec, 3);
5873 static const WCHAR Name[] = {'N','a','m','e',0};
5874 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5875 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5876 static const WCHAR PublicKeyToken[] = {
5877 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5879 if (!lstrcmpW(name, Name))
5880 asmname->name = val;
5881 else if (!lstrcmpW(name, Version))
5882 asmname->version = val;
5883 else if (!lstrcmpW(name, Culture))
5884 asmname->culture = val;
5885 else if (!lstrcmpW(name, PublicKeyToken))
5886 asmname->pubkeytoken = val;
5887 else
5888 msi_free(val);
5890 return ERROR_SUCCESS;
5893 static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5895 if (!*str)
5897 *size = lstrlenW(append) + 1;
5898 *str = msi_alloc((*size) * sizeof(WCHAR));
5899 lstrcpyW(*str, append);
5900 return;
5903 (*size) += lstrlenW(append);
5904 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5905 lstrcatW(*str, append);
5908 static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5909 MSICOMPONENT *comp)
5911 ASSEMBLY_INFO asminfo;
5912 ASSEMBLY_NAME name;
5913 MSIQUERY *view;
5914 LPWSTR disp;
5915 DWORD size;
5916 BOOL found;
5917 UINT r;
5919 static const WCHAR separator[] = {',',' ',0};
5920 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5921 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5922 static const WCHAR PublicKeyToken[] = {
5923 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5924 static const WCHAR query[] = {
5925 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5926 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5927 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5928 '=','\'','%','s','\'',0};
5930 disp = NULL;
5931 found = FALSE;
5932 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5933 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5935 r = MSI_OpenQuery(db, &view, query, comp->Component);
5936 if (r != ERROR_SUCCESS)
5937 return ERROR_SUCCESS;
5939 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
5940 msiobj_release(&view->hdr);
5942 if (!name.name)
5944 ERR("No assembly name specified!\n");
5945 goto done;
5948 append_str(&disp, &size, name.name);
5950 if (name.version)
5952 append_str(&disp, &size, separator);
5953 append_str(&disp, &size, Version);
5954 append_str(&disp, &size, name.version);
5957 if (name.culture)
5959 append_str(&disp, &size, separator);
5960 append_str(&disp, &size, Culture);
5961 append_str(&disp, &size, name.culture);
5964 if (name.pubkeytoken)
5966 append_str(&disp, &size, separator);
5967 append_str(&disp, &size, PublicKeyToken);
5968 append_str(&disp, &size, name.pubkeytoken);
5971 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
5972 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
5973 disp, &asminfo);
5974 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
5976 done:
5977 msiobj_release(&view->hdr);
5978 msi_free(disp);
5979 msi_free(name.name);
5980 msi_free(name.version);
5981 msi_free(name.culture);
5982 msi_free(name.pubkeytoken);
5984 return found;
5987 static UINT load_assembly(MSIRECORD *rec, LPVOID param)
5989 ASSEMBLY_LIST *list = (ASSEMBLY_LIST *)param;
5990 MSIASSEMBLY *assembly;
5992 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
5993 if (!assembly)
5994 return ERROR_OUTOFMEMORY;
5996 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
5998 if (!assembly->component || !assembly->component->Enabled ||
5999 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
6001 TRACE("Component not set for install, not publishing assembly\n");
6002 msi_free(assembly);
6003 return ERROR_SUCCESS;
6006 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6007 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
6009 if (!assembly->file)
6011 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6012 return ERROR_FUNCTION_FAILED;
6015 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6016 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6017 assembly->attributes = MSI_RecordGetInteger(rec, 5);
6018 assembly->installed = check_assembly_installed(list->package->db,
6019 list->cache,
6020 assembly->component);
6022 list_add_head(list->assemblies, &assembly->entry);
6023 return ERROR_SUCCESS;
6026 static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6028 IAssemblyCache *cache = NULL;
6029 ASSEMBLY_LIST list;
6030 MSIQUERY *view;
6031 HRESULT hr;
6032 UINT r;
6034 static const WCHAR query[] =
6035 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6036 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6038 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6039 if (r != ERROR_SUCCESS)
6040 return ERROR_SUCCESS;
6042 hr = pCreateAssemblyCache(&cache, 0);
6043 if (FAILED(hr))
6044 return ERROR_FUNCTION_FAILED;
6046 list.package = package;
6047 list.cache = cache;
6048 list.assemblies = assemblies;
6050 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6051 msiobj_release(&view->hdr);
6053 IAssemblyCache_Release(cache);
6055 return r;
6058 static void free_assemblies(struct list *assemblies)
6060 struct list *item, *cursor;
6062 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6064 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6066 list_remove(&assembly->entry);
6067 msi_free(assembly->application);
6068 msi_free(assembly->manifest);
6069 msi_free(assembly);
6073 static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6075 MSIASSEMBLY *assembly;
6077 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6079 if (!lstrcmpW(assembly->file->File, file))
6081 *out = assembly;
6082 return TRUE;
6086 return FALSE;
6089 static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6090 LPWSTR *path, DWORD *attrs, PVOID user)
6092 MSIASSEMBLY *assembly;
6093 WCHAR temppath[MAX_PATH];
6094 struct list *assemblies = (struct list *)user;
6095 UINT r;
6097 if (!find_assembly(assemblies, file, &assembly))
6098 return FALSE;
6100 GetTempPathW(MAX_PATH, temppath);
6101 PathAddBackslashW(temppath);
6102 lstrcatW(temppath, assembly->file->FileName);
6104 if (action == MSICABEXTRACT_BEGINEXTRACT)
6106 if (assembly->installed)
6107 return FALSE;
6109 *path = strdupW(temppath);
6110 *attrs = assembly->file->Attributes;
6112 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6114 assembly->installed = TRUE;
6116 r = install_assembly(package, assembly, temppath);
6117 if (r != ERROR_SUCCESS)
6118 ERR("Failed to install assembly\n");
6121 return TRUE;
6124 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6126 UINT r;
6127 struct list assemblies = LIST_INIT(assemblies);
6128 MSIASSEMBLY *assembly;
6129 MSIMEDIAINFO *mi;
6131 if (!init_functionpointers() || !pCreateAssemblyCache)
6132 return ERROR_FUNCTION_FAILED;
6134 r = load_assemblies(package, &assemblies);
6135 if (r != ERROR_SUCCESS)
6136 goto done;
6138 if (list_empty(&assemblies))
6139 goto done;
6141 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6142 if (!mi)
6144 r = ERROR_OUTOFMEMORY;
6145 goto done;
6148 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6150 if (assembly->installed && !mi->is_continuous)
6151 continue;
6153 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6154 (assembly->file->IsCompressed && !mi->is_extracted))
6156 MSICABDATA data;
6158 r = ready_media(package, assembly->file, mi);
6159 if (r != ERROR_SUCCESS)
6161 ERR("Failed to ready media\n");
6162 break;
6165 data.mi = mi;
6166 data.package = package;
6167 data.cb = installassembly_cb;
6168 data.user = &assemblies;
6170 if (assembly->file->IsCompressed &&
6171 !msi_cabextract(package, mi, &data))
6173 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6174 r = ERROR_FUNCTION_FAILED;
6175 break;
6179 if (!assembly->file->IsCompressed)
6181 LPWSTR source = resolve_file_source(package, assembly->file);
6183 r = install_assembly(package, assembly, source);
6184 if (r != ERROR_SUCCESS)
6185 ERR("Failed to install assembly\n");
6187 msi_free(source);
6190 /* FIXME: write Installer assembly reg values */
6193 done:
6194 free_assemblies(&assemblies);
6195 return r;
6198 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6199 LPCSTR action, LPCWSTR table )
6201 static const WCHAR query[] = {
6202 'S','E','L','E','C','T',' ','*',' ',
6203 'F','R','O','M',' ','`','%','s','`',0 };
6204 MSIQUERY *view = NULL;
6205 DWORD count = 0;
6206 UINT r;
6208 r = MSI_OpenQuery( package->db, &view, query, table );
6209 if (r == ERROR_SUCCESS)
6211 r = MSI_IterateRecords(view, &count, NULL, package);
6212 msiobj_release(&view->hdr);
6215 if (count)
6216 FIXME("%s -> %u ignored %s table values\n",
6217 action, count, debugstr_w(table));
6219 return ERROR_SUCCESS;
6222 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6224 TRACE("%p\n", package);
6225 return ERROR_SUCCESS;
6228 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
6230 static const WCHAR table[] =
6231 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6232 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6235 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6237 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6238 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6241 static UINT ACTION_BindImage( MSIPACKAGE *package )
6243 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6244 return msi_unimplemented_action_stub( package, "BindImage", table );
6247 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6249 static const WCHAR table[] = {
6250 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6251 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6254 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6256 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6257 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6260 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
6262 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6263 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6266 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6268 static const WCHAR table[] = {
6269 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6270 return msi_unimplemented_action_stub( package, "DeleteServices", table );
6272 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6274 static const WCHAR table[] = {
6275 'P','r','o','d','u','c','t','I','D',0 };
6276 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6279 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6281 static const WCHAR table[] = {
6282 'E','n','v','i','r','o','n','m','e','n','t',0 };
6283 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6286 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6288 static const WCHAR table[] = {
6289 'M','s','i','A','s','s','e','m','b','l','y',0 };
6290 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6293 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6295 static const WCHAR table[] = { 'F','o','n','t',0 };
6296 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6299 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6301 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6302 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6305 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6307 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6308 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6311 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6313 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6314 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6317 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6319 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6320 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6323 static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6325 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6326 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6329 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6331 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6332 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6335 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6337 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6338 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6341 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6343 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6344 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6347 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6349 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6350 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6353 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6355 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6356 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6359 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6361 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6362 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6365 static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6367 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6368 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6371 static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6373 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6374 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6377 static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6379 static const WCHAR table[] = { 'M','I','M','E',0 };
6380 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6383 static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6385 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6386 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6389 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6391 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6392 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6395 static const struct _actions StandardActions[] = {
6396 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6397 { szAppSearch, ACTION_AppSearch },
6398 { szBindImage, ACTION_BindImage },
6399 { szCCPSearch, ACTION_CCPSearch },
6400 { szCostFinalize, ACTION_CostFinalize },
6401 { szCostInitialize, ACTION_CostInitialize },
6402 { szCreateFolders, ACTION_CreateFolders },
6403 { szCreateShortcuts, ACTION_CreateShortcuts },
6404 { szDeleteServices, ACTION_DeleteServices },
6405 { szDisableRollback, NULL },
6406 { szDuplicateFiles, ACTION_DuplicateFiles },
6407 { szExecuteAction, ACTION_ExecuteAction },
6408 { szFileCost, ACTION_FileCost },
6409 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6410 { szForceReboot, ACTION_ForceReboot },
6411 { szInstallAdminPackage, NULL },
6412 { szInstallExecute, ACTION_InstallExecute },
6413 { szInstallExecuteAgain, ACTION_InstallExecute },
6414 { szInstallFiles, ACTION_InstallFiles},
6415 { szInstallFinalize, ACTION_InstallFinalize },
6416 { szInstallInitialize, ACTION_InstallInitialize },
6417 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6418 { szInstallValidate, ACTION_InstallValidate },
6419 { szIsolateComponents, ACTION_IsolateComponents },
6420 { szLaunchConditions, ACTION_LaunchConditions },
6421 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6422 { szMoveFiles, ACTION_MoveFiles },
6423 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6424 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6425 { szInstallODBC, ACTION_InstallODBC },
6426 { szInstallServices, ACTION_InstallServices },
6427 { szPatchFiles, ACTION_PatchFiles },
6428 { szProcessComponents, ACTION_ProcessComponents },
6429 { szPublishComponents, ACTION_PublishComponents },
6430 { szPublishFeatures, ACTION_PublishFeatures },
6431 { szPublishProduct, ACTION_PublishProduct },
6432 { szRegisterClassInfo, ACTION_RegisterClassInfo },
6433 { szRegisterComPlus, ACTION_RegisterComPlus},
6434 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6435 { szRegisterFonts, ACTION_RegisterFonts },
6436 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6437 { szRegisterProduct, ACTION_RegisterProduct },
6438 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6439 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6440 { szRegisterUser, ACTION_RegisterUser },
6441 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6442 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6443 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6444 { szRemoveFiles, ACTION_RemoveFiles },
6445 { szRemoveFolders, ACTION_RemoveFolders },
6446 { szRemoveIniValues, ACTION_RemoveIniValues },
6447 { szRemoveODBC, ACTION_RemoveODBC },
6448 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6449 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6450 { szResolveSource, ACTION_ResolveSource },
6451 { szRMCCPSearch, ACTION_RMCCPSearch },
6452 { szScheduleReboot, NULL },
6453 { szSelfRegModules, ACTION_SelfRegModules },
6454 { szSelfUnregModules, ACTION_SelfUnregModules },
6455 { szSetODBCFolders, NULL },
6456 { szStartServices, ACTION_StartServices },
6457 { szStopServices, ACTION_StopServices },
6458 { szUnpublishComponents, ACTION_UnpublishComponents },
6459 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6460 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6461 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6462 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6463 { szUnregisterFonts, ACTION_UnregisterFonts },
6464 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6465 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6466 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6467 { szValidateProductID, ACTION_ValidateProductID },
6468 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6469 { szWriteIniValues, ACTION_WriteIniValues },
6470 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6471 { NULL, NULL },
6474 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6475 UINT* rc, BOOL force )
6477 BOOL ret = FALSE;
6478 BOOL run = force;
6479 int i;
6481 if (!run && !package->script->CurrentlyScripting)
6482 run = TRUE;
6484 if (!run)
6486 if (strcmpW(action,szInstallFinalize) == 0 ||
6487 strcmpW(action,szInstallExecute) == 0 ||
6488 strcmpW(action,szInstallExecuteAgain) == 0)
6489 run = TRUE;
6492 i = 0;
6493 while (StandardActions[i].action != NULL)
6495 if (strcmpW(StandardActions[i].action, action)==0)
6497 if (!run)
6499 ui_actioninfo(package, action, TRUE, 0);
6500 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6501 ui_actioninfo(package, action, FALSE, *rc);
6503 else
6505 ui_actionstart(package, action);
6506 if (StandardActions[i].handler)
6508 *rc = StandardActions[i].handler(package);
6510 else
6512 FIXME("unhandled standard action %s\n",debugstr_w(action));
6513 *rc = ERROR_SUCCESS;
6516 ret = TRUE;
6517 break;
6519 i++;
6521 return ret;