mshtml: Moved QueryService call to hlink_frame_navigate.
[wine] / dlls / msi / action.c
CommitLineData
401bd3f7
AS
1/*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
c6689520 4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
401bd3f7
AS
5 *
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.
10 *
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.
15 *
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
360a3f91 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
401bd3f7
AS
19 */
20
401bd3f7 21#include <stdarg.h>
401bd3f7 22
486d020c
FG
23#define COBJMACROS
24
401bd3f7
AS
25#include "windef.h"
26#include "winbase.h"
27#include "winerror.h"
28#include "winreg.h"
9bc12ade 29#include "winsvc.h"
d3bec325 30#include "odbcinst.h"
401bd3f7 31#include "wine/debug.h"
b6bc6aa6 32#include "msidefs.h"
401bd3f7 33#include "msipriv.h"
401bd3f7
AS
34#include "winuser.h"
35#include "shlobj.h"
bfe07d1d
JH
36#include "objbase.h"
37#include "mscoree.h"
38#include "fusion.h"
39#include "shlwapi.h"
401bd3f7 40#include "wine/unicode.h"
98efef18 41#include "winver.h"
401bd3f7 42
bd1bbc17
AS
43#define REG_PROGRESS_VALUE 13200
44#define COMPONENT_PROGRESS_VALUE 24000
401bd3f7 45
401bd3f7
AS
46WINE_DEFAULT_DEBUG_CHANNEL(msi);
47
48/*
49 * Prototypes
50 */
a7a6f5f3
AJ
51static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
52static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
f8f64406 53static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
9e85ec3b 54static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
90c57396 55
401bd3f7
AS
56/*
57 * consts and values used
58 */
014ad3ba 59static const WCHAR c_colon[] = {'C',':','\\',0};
c6689520 60
9ba8ba30 61static const WCHAR szCreateFolders[] =
8e233e9b 62 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
9ba8ba30 63static const WCHAR szCostFinalize[] =
8e233e9b 64 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
c6689520 65const WCHAR szInstallFiles[] =
8e233e9b 66 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
c6689520 67const WCHAR szDuplicateFiles[] =
8e233e9b 68 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
9ba8ba30 69static const WCHAR szWriteRegistryValues[] =
8e233e9b
AS
70 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
71 'V','a','l','u','e','s',0};
9ba8ba30 72static const WCHAR szCostInitialize[] =
8e233e9b 73 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
9ba8ba30 74static const WCHAR szFileCost[] =
8e233e9b 75 {'F','i','l','e','C','o','s','t',0};
9ba8ba30 76static const WCHAR szInstallInitialize[] =
8e233e9b 77 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
9ba8ba30 78static const WCHAR szInstallValidate[] =
8e233e9b 79 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
9ba8ba30 80static const WCHAR szLaunchConditions[] =
8e233e9b 81 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
9ba8ba30 82static const WCHAR szProcessComponents[] =
8e233e9b 83 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
9ba8ba30 84static const WCHAR szRegisterTypeLibraries[] =
8e233e9b
AS
85 {'R','e','g','i','s','t','e','r','T','y','p','e',
86 'L','i','b','r','a','r','i','e','s',0};
db982e25 87const WCHAR szRegisterClassInfo[] =
8e233e9b 88 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
db982e25 89const WCHAR szRegisterProgIdInfo[] =
8e233e9b 90 {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
9ba8ba30 91static const WCHAR szCreateShortcuts[] =
8e233e9b 92 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
9ba8ba30 93static const WCHAR szPublishProduct[] =
8e233e9b 94 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
9ba8ba30 95static const WCHAR szWriteIniValues[] =
8e233e9b 96 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
9ba8ba30 97static const WCHAR szSelfRegModules[] =
8e233e9b 98 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
9ba8ba30 99static const WCHAR szPublishFeatures[] =
8e233e9b 100 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
9ba8ba30 101static const WCHAR szRegisterProduct[] =
8e233e9b 102 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
9ba8ba30 103static const WCHAR szInstallExecute[] =
8e233e9b 104 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
9ba8ba30 105static const WCHAR szInstallExecuteAgain[] =
8e233e9b
AS
106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
107 'A','g','a','i','n',0};
9ba8ba30 108static const WCHAR szInstallFinalize[] =
8e233e9b 109 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
9ba8ba30 110static const WCHAR szForceReboot[] =
8e233e9b 111 {'F','o','r','c','e','R','e','b','o','o','t',0};
9ba8ba30 112static const WCHAR szResolveSource[] =
8e233e9b 113 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
b79a53e9 114static const WCHAR szAppSearch[] =
8e233e9b 115 {'A','p','p','S','e','a','r','c','h',0};
9ba8ba30 116static const WCHAR szAllocateRegistrySpace[] =
8e233e9b
AS
117 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
118 'S','p','a','c','e',0};
9ba8ba30 119static const WCHAR szBindImage[] =
8e233e9b 120 {'B','i','n','d','I','m','a','g','e',0};
9ba8ba30 121static const WCHAR szCCPSearch[] =
8e233e9b 122 {'C','C','P','S','e','a','r','c','h',0};
9ba8ba30 123static const WCHAR szDeleteServices[] =
8e233e9b 124 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
9ba8ba30 125static const WCHAR szDisableRollback[] =
8e233e9b 126 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
9ba8ba30 127static const WCHAR szExecuteAction[] =
8e233e9b 128 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
db982e25 129const WCHAR szFindRelatedProducts[] =
8e233e9b
AS
130 {'F','i','n','d','R','e','l','a','t','e','d',
131 'P','r','o','d','u','c','t','s',0};
9ba8ba30 132static const WCHAR szInstallAdminPackage[] =
8e233e9b
AS
133 {'I','n','s','t','a','l','l','A','d','m','i','n',
134 'P','a','c','k','a','g','e',0};
9ba8ba30 135static const WCHAR szInstallSFPCatalogFile[] =
8e233e9b
AS
136 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
137 'F','i','l','e',0};
9ba8ba30 138static const WCHAR szIsolateComponents[] =
8e233e9b 139 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
c6689520 140const WCHAR szMigrateFeatureStates[] =
8e233e9b
AS
141 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
142 'S','t','a','t','e','s',0};
c6689520 143const WCHAR szMoveFiles[] =
8e233e9b 144 {'M','o','v','e','F','i','l','e','s',0};
9ba8ba30 145static const WCHAR szMsiPublishAssemblies[] =
8e233e9b
AS
146 {'M','s','i','P','u','b','l','i','s','h',
147 'A','s','s','e','m','b','l','i','e','s',0};
9ba8ba30 148static const WCHAR szMsiUnpublishAssemblies[] =
8e233e9b
AS
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};
9ba8ba30 151static const WCHAR szInstallODBC[] =
8e233e9b 152 {'I','n','s','t','a','l','l','O','D','B','C',0};
9ba8ba30 153static const WCHAR szInstallServices[] =
8e233e9b 154 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
c6689520 155const WCHAR szPatchFiles[] =
8e233e9b 156 {'P','a','t','c','h','F','i','l','e','s',0};
9ba8ba30 157static const WCHAR szPublishComponents[] =
8e233e9b 158 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
9ba8ba30 159static const WCHAR szRegisterComPlus[] =
8e233e9b 160 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
db982e25 161const WCHAR szRegisterExtensionInfo[] =
8e233e9b
AS
162 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
163 'I','n','f','o',0};
9ba8ba30 164static const WCHAR szRegisterFonts[] =
8e233e9b 165 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
db982e25 166const WCHAR szRegisterMIMEInfo[] =
8e233e9b 167 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
9ba8ba30 168static const WCHAR szRegisterUser[] =
8e233e9b 169 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
c6689520 170const WCHAR szRemoveDuplicateFiles[] =
8e233e9b
AS
171 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
172 'F','i','l','e','s',0};
9ba8ba30 173static const WCHAR szRemoveEnvironmentStrings[] =
8e233e9b
AS
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};
c6689520 176const WCHAR szRemoveExistingProducts[] =
8e233e9b
AS
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};
c6689520 179const WCHAR szRemoveFiles[] =
8e233e9b 180 {'R','e','m','o','v','e','F','i','l','e','s',0};
9ba8ba30 181static const WCHAR szRemoveFolders[] =
8e233e9b 182 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
9ba8ba30 183static const WCHAR szRemoveIniValues[] =
8e233e9b 184 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
9ba8ba30 185static const WCHAR szRemoveODBC[] =
8e233e9b 186 {'R','e','m','o','v','e','O','D','B','C',0};
9ba8ba30 187static const WCHAR szRemoveRegistryValues[] =
8e233e9b
AS
188 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
189 'V','a','l','u','e','s',0};
9ba8ba30 190static const WCHAR szRemoveShortcuts[] =
8e233e9b 191 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
9ba8ba30 192static const WCHAR szRMCCPSearch[] =
8e233e9b 193 {'R','M','C','C','P','S','e','a','r','c','h',0};
9ba8ba30 194static const WCHAR szScheduleReboot[] =
8e233e9b 195 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
9ba8ba30 196static const WCHAR szSelfUnregModules[] =
8e233e9b 197 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
9ba8ba30 198static const WCHAR szSetODBCFolders[] =
8e233e9b 199 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
9ba8ba30 200static const WCHAR szStartServices[] =
8e233e9b 201 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
9ba8ba30 202static const WCHAR szStopServices[] =
8e233e9b 203 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
9ba8ba30 204static const WCHAR szUnpublishComponents[] =
8e233e9b
AS
205 {'U','n','p','u','b','l','i','s','h',
206 'C','o','m','p','o','n','e','n','t','s',0};
9ba8ba30 207static const WCHAR szUnpublishFeatures[] =
8e233e9b 208 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
c6689520 209const WCHAR szUnregisterClassInfo[] =
8e233e9b
AS
210 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
211 'I','n','f','o',0};
9ba8ba30 212static const WCHAR szUnregisterComPlus[] =
8e233e9b 213 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
c6689520 214const WCHAR szUnregisterExtensionInfo[] =
8e233e9b
AS
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};
9ba8ba30 217static const WCHAR szUnregisterFonts[] =
8e233e9b 218 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
c6689520 219const WCHAR szUnregisterMIMEInfo[] =
8e233e9b 220 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
c6689520 221const WCHAR szUnregisterProgIdInfo[] =
8e233e9b
AS
222 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
223 'I','n','f','o',0};
9ba8ba30 224static const WCHAR szUnregisterTypeLibraries[] =
8e233e9b
AS
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};
9ba8ba30 227static const WCHAR szValidateProductID[] =
8e233e9b 228 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
9ba8ba30 229static const WCHAR szWriteEnvironmentStrings[] =
8e233e9b
AS
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};
90c57396 232
3b955150
MM
233/* action handlers */
234typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
235
90c57396
AS
236struct _actions {
237 LPCWSTR action;
238 STANDARDACTIONHANDLER handler;
239};
240
2703d717
AS
241
242/********************************************************
243 * helper functions
244 ********************************************************/
245
a7a6f5f3 246static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
d2c395ad 247{
d2c395ad 248 static const WCHAR Query_t[] =
8e233e9b 249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082
AS
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};
d679bc5a 253 MSIRECORD * row;
d2c395ad 254
0b352c7f
MM
255 row = MSI_QueryGetRecord( package->db, Query_t, action );
256 if (!row)
d2c395ad 257 return;
a7a6f5f3
AJ
258 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
259 msiobj_release(&row->hdr);
d2c395ad
AS
260}
261
a7a6f5f3 262static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
d2c395ad
AS
263 UINT rc)
264{
a7a6f5f3 265 MSIRECORD * row;
d2c395ad 266 static const WCHAR template_s[]=
8e233e9b
AS
267 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
268 '%','s', '.',0};
d2c395ad 269 static const WCHAR template_e[]=
8e233e9b
AS
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};
d2c395ad 273 static const WCHAR format[] =
8e233e9b 274 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
d2c395ad
AS
275 WCHAR message[1024];
276 WCHAR timet[0x100];
277
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);
283
a7a6f5f3
AJ
284 row = MSI_CreateRecord(1);
285 MSI_RecordSetStringW(row,1,message);
d2c395ad 286
a7a6f5f3
AJ
287 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
288 msiobj_release(&row->hdr);
d2c395ad
AS
289}
290
ca71e5af
JH
291UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
292 BOOL preserve_case )
e3452228
MM
293{
294 LPCWSTR ptr,ptr2;
295 BOOL quote;
296 DWORD len;
297 LPWSTR prop = NULL, val = NULL;
298
299 if (!szCommandLine)
300 return ERROR_SUCCESS;
301
302 ptr = szCommandLine;
303
304 while (*ptr)
305 {
306 if (*ptr==' ')
307 {
308 ptr++;
309 continue;
310 }
311
312 TRACE("Looking at %s\n",debugstr_w(ptr));
313
314 ptr2 = strchrW(ptr,'=');
315 if (!ptr2)
316 {
317 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
318 break;
319 }
320
321 quote = FALSE;
322
323 len = ptr2-ptr;
324 prop = msi_alloc((len+1)*sizeof(WCHAR));
325 memcpy(prop,ptr,len*sizeof(WCHAR));
326 prop[len]=0;
ca71e5af
JH
327
328 if (!preserve_case)
329 struprW(prop);
330
e3452228
MM
331 ptr2++;
332
333 len = 0;
334 ptr = ptr2;
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
336 {
337 if (*ptr == '"')
338 quote = !quote;
339 ptr++;
340 len++;
341 }
342
343 if (*ptr2=='"')
344 {
345 ptr2++;
346 len -= 2;
347 }
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
350 val[len] = 0;
351
352 if (lstrlenW(prop) > 0)
353 {
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
357 }
358 msi_free(val);
359 msi_free(prop);
360 }
361
362 return ERROR_SUCCESS;
363}
364
965a72ad
MM
365
366static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367{
2e372c08 368 LPCWSTR pc;
965a72ad
MM
369 LPWSTR p, *ret = NULL;
370 UINT count = 0;
371
372 if (!str)
373 return ret;
374
375 /* count the number of substrings */
2e372c08 376 for ( pc = str, count = 0; pc; count++ )
965a72ad 377 {
2e372c08
AT
378 pc = strchrW( pc, sep );
379 if (pc)
380 pc++;
965a72ad
MM
381 }
382
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;
388
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++ )
393 {
394 p = strchrW( p, sep );
395 if (p)
396 *p++ = 0;
397 }
398
399 return ret;
400}
401
0d7dc8f9
MM
402static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
403{
86af8769
HL
404 static const WCHAR szProductCode[] =
405 { 'P','r','o','d','u','c','t','C','o','d','e',0 };
406 static const WCHAR szSystemLanguageID[] =
407 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
408
409 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
410 UINT ret = ERROR_FUNCTION_FAILED;
0d7dc8f9
MM
411
412 prod_code = msi_dup_property( package, szProductCode );
413 patch_product = msi_get_suminfo_product( patch );
414
415 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
416
417 if ( strstrW( patch_product, prod_code ) )
86af8769
HL
418 {
419 static const WCHAR zero[] = {'0',0};
420 MSISUMMARYINFO *si;
421 const WCHAR *p;
422
423 si = MSI_GetSummaryInformationW( patch, 0 );
424 if (!si)
425 {
426 ERR("no summary information!\n");
427 goto end;
428 }
429
430 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
431 if (!template)
432 {
433 ERR("no template property!\n");
434 msiobj_release( &si->hdr );
435 goto end;
436 }
437
438 if (!template[0])
439 {
440 ret = ERROR_SUCCESS;
441 msiobj_release( &si->hdr );
442 goto end;
443 }
444
445 langid = msi_dup_property( package, szSystemLanguageID );
446 if (!langid)
447 {
448 msiobj_release( &si->hdr );
449 goto end;
450 }
451
452 p = strchrW( template, ';' );
453 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, zero )))
454 {
455 TRACE("applicable transform\n");
456 ret = ERROR_SUCCESS;
457 }
458
459 /* FIXME: check platform */
460
461 msiobj_release( &si->hdr );
462 }
0d7dc8f9 463
86af8769 464end:
0d7dc8f9
MM
465 msi_free( patch_product );
466 msi_free( prod_code );
86af8769
HL
467 msi_free( template );
468 msi_free( langid );
0d7dc8f9
MM
469
470 return ret;
471}
472
965a72ad
MM
473static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
474 MSIDATABASE *patch_db, LPCWSTR name )
475{
476 UINT ret = ERROR_FUNCTION_FAILED;
477 IStorage *stg = NULL;
478 HRESULT r;
479
480 TRACE("%p %s\n", package, debugstr_w(name) );
481
482 if (*name++ != ':')
483 {
484 ERR("expected a colon in %s\n", debugstr_w(name));
485 return ERROR_FUNCTION_FAILED;
486 }
487
488 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
489 if (SUCCEEDED(r))
490 {
0d7dc8f9
MM
491 ret = msi_check_transform_applicable( package, stg );
492 if (ret == ERROR_SUCCESS)
493 msi_table_apply_transform( package->db, stg );
494 else
495 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
965a72ad 496 IStorage_Release( stg );
965a72ad
MM
497 }
498 else
499 ERR("failed to open substorage %s\n", debugstr_w(name));
500
0d7dc8f9 501 return ERROR_SUCCESS;
965a72ad
MM
502}
503
05e9a1fc 504UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
965a72ad 505{
261e1179
JH
506 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
507 LPWSTR guid_list, *guids, product_code;
965a72ad
MM
508 UINT i, ret = ERROR_FUNCTION_FAILED;
509
261e1179
JH
510 product_code = msi_dup_property( package, szProdCode );
511 if (!product_code)
965a72ad 512 {
261e1179
JH
513 /* FIXME: the property ProductCode should be written into the DB somewhere */
514 ERR("no product code to check\n");
965a72ad
MM
515 return ERROR_SUCCESS;
516 }
517
518 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
519 guids = msi_split_string( guid_list, ';' );
520 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
521 {
261e1179 522 if (!lstrcmpW( guids[i], product_code ))
965a72ad
MM
523 ret = ERROR_SUCCESS;
524 }
525 msi_free( guids );
526 msi_free( guid_list );
261e1179 527 msi_free( product_code );
965a72ad
MM
528
529 return ret;
530}
531
c059ceb5
JH
532static UINT msi_set_media_source_prop(MSIPACKAGE *package)
533{
534 MSIQUERY *view;
535 MSIRECORD *rec = NULL;
536 LPWSTR patch;
537 LPCWSTR prop;
538 UINT r;
539
540 static const WCHAR szPatch[] = {'P','A','T','C','H',0};
541 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
542 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
543 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
544 '`','S','o','u','r','c','e','`',' ','I','S',' ',
545 'N','O','T',' ','N','U','L','L',0};
546
547 r = MSI_DatabaseOpenViewW(package->db, query, &view);
548 if (r != ERROR_SUCCESS)
549 return r;
550
551 r = MSI_ViewExecute(view, 0);
552 if (r != ERROR_SUCCESS)
553 goto done;
554
555 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
556 {
557 prop = MSI_RecordGetString(rec, 1);
558 patch = msi_dup_property(package, szPatch);
559 MSI_SetPropertyW(package, prop, patch);
560 msi_free(patch);
561 }
562
563done:
564 if (rec) msiobj_release(&rec->hdr);
565 msiobj_release(&view->hdr);
566
567 return r;
568}
569
965a72ad
MM
570static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
571{
572 MSISUMMARYINFO *si;
573 LPWSTR str, *substorage;
574 UINT i, r = ERROR_SUCCESS;
575
7f98f1d0 576 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
965a72ad
MM
577 if (!si)
578 return ERROR_FUNCTION_FAILED;
579
01eb9300
JH
580 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
581 {
582 TRACE("Patch not applicable\n");
583 return ERROR_SUCCESS;
584 }
585
586 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
587 if (!package->patch)
588 return ERROR_OUTOFMEMORY;
589
590 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
591 if (!package->patch->patchcode)
592 return ERROR_OUTOFMEMORY;
965a72ad
MM
593
594 /* enumerate the substorage */
595 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
01eb9300
JH
596 package->patch->transforms = str;
597
965a72ad
MM
598 substorage = msi_split_string( str, ';' );
599 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
600 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
965a72ad 601
01eb9300 602 msi_free( substorage );
965a72ad
MM
603 msiobj_release( &si->hdr );
604
c059ceb5
JH
605 msi_set_media_source_prop(package);
606
965a72ad
MM
607 return r;
608}
609
610static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
611{
612 MSIDATABASE *patch_db = NULL;
613 UINT r;
614
615 TRACE("%p %s\n", package, debugstr_w( file ) );
616
617 /* FIXME:
618 * We probably want to make sure we only open a patch collection here.
619 * Patch collections (.msp) and databases (.msi) have different GUIDs
620 * but currently MSI_OpenDatabaseW will accept both.
621 */
622 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
623 if ( r != ERROR_SUCCESS )
624 {
625 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
626 return r;
627 }
628
629 msi_parse_patch_summary( package, patch_db );
9a4ba8c1
MM
630
631 /*
632 * There might be a CAB file in the patch package,
633 * so append it to the list of storage to search for streams.
634 */
635 append_storage_to_db( package->db, patch_db->storage );
636
965a72ad
MM
637 msiobj_release( &patch_db->hdr );
638
639 return ERROR_SUCCESS;
640}
641
642/* get the PATCH property, and apply all the patches it specifies */
643static UINT msi_apply_patches( MSIPACKAGE *package )
644{
645 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
646 LPWSTR patch_list, *patches;
647 UINT i, r = ERROR_SUCCESS;
648
649 patch_list = msi_dup_property( package, szPatch );
650
651 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
652
653 patches = msi_split_string( patch_list, ';' );
654 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
655 r = msi_apply_patch_package( package, patches[i] );
656
657 msi_free( patches );
658 msi_free( patch_list );
659
660 return r;
661}
662
e534e772
MM
663static UINT msi_apply_transforms( MSIPACKAGE *package )
664{
665 static const WCHAR szTransforms[] = {
666 'T','R','A','N','S','F','O','R','M','S',0 };
667 LPWSTR xform_list, *xforms;
668 UINT i, r = ERROR_SUCCESS;
669
670 xform_list = msi_dup_property( package, szTransforms );
671 xforms = msi_split_string( xform_list, ';' );
672
673 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
674 {
675 if (xforms[i][0] == ':')
776a7d70 676 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
e534e772
MM
677 else
678 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
679 }
680
681 msi_free( xforms );
682 msi_free( xform_list );
683
684 return r;
685}
686
4439e0b5 687static BOOL ui_sequence_exists( MSIPACKAGE *package )
6da8041d
JH
688{
689 MSIQUERY *view;
690 UINT rc;
691
692 static const WCHAR ExecSeqQuery [] =
693 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
694 '`','I','n','s','t','a','l','l',
695 'U','I','S','e','q','u','e','n','c','e','`',
696 ' ','W','H','E','R','E',' ',
697 '`','S','e','q','u','e','n','c','e','`',' ',
698 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
699 '`','S','e','q','u','e','n','c','e','`',0};
700
701 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
702 if (rc == ERROR_SUCCESS)
703 {
704 msiobj_release(&view->hdr);
705 return TRUE;
706 }
707
708 return FALSE;
709}
710
c777d309
JH
711static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
712{
062070bf 713 LPWSTR p, db;
c777d309
JH
714 LPWSTR source, check;
715 DWORD len;
716
c37849ad
JH
717 static const WCHAR szOriginalDatabase[] =
718 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
719
062070bf
JH
720 db = msi_dup_property( package, szOriginalDatabase );
721 if (!db)
722 return ERROR_OUTOFMEMORY;
723
724 p = strrchrW( db, '\\' );
c777d309 725 if (!p)
062070bf 726 {
18648766
JH
727 p = strrchrW( db, '/' );
728 if (!p)
729 {
730 msi_free(db);
731 return ERROR_SUCCESS;
732 }
062070bf 733 }
c777d309 734
062070bf 735 len = p - db + 2;
c777d309 736 source = msi_alloc( len * sizeof(WCHAR) );
062070bf 737 lstrcpynW( source, db, len );
c777d309
JH
738
739 check = msi_dup_property( package, cszSourceDir );
740 if (!check || replace)
741 MSI_SetPropertyW( package, cszSourceDir, source );
742
743 msi_free( check );
744
745 check = msi_dup_property( package, cszSOURCEDIR );
746 if (!check || replace)
747 MSI_SetPropertyW( package, cszSOURCEDIR, source );
748
749 msi_free( check );
750 msi_free( source );
062070bf 751 msi_free( db );
c777d309
JH
752
753 return ERROR_SUCCESS;
754}
755
5f11262d
JH
756static UINT msi_set_context(MSIPACKAGE *package)
757{
758 WCHAR val[10];
759 DWORD sz = 10;
760 DWORD num;
761 UINT r;
762
763 static const WCHAR szOne[] = {'1',0};
764 static const WCHAR szAllUsers[] = {'A','L','L','U','S','E','R','S',0};
765
766 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
767
768 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
769 if (r == ERROR_SUCCESS)
770 {
771 num = atolW(val);
772 if (num == 1 || num == 2)
773 package->Context = MSIINSTALLCONTEXT_MACHINE;
774 }
775
776 MSI_SetPropertyW(package, szAllUsers, szOne);
777 return ERROR_SUCCESS;
778}
779
401bd3f7
AS
780/****************************************************
781 * TOP level entry points
782 *****************************************************/
783
61f24a4c
MM
784UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
785 LPCWSTR szCommandLine )
401bd3f7 786{
401bd3f7 787 UINT rc;
6da8041d 788 BOOL ui = FALSE, ui_exists;
a7a6f5f3 789 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
6269f00c
AS
790 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
791 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
1169aa9a
HL
792 static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
793 static const WCHAR szInstalled[] = {'I','n','s','t','a','l','l','e','d',0};
794 static const WCHAR szAll[] = {'A','L','L',0};
6269f00c
AS
795
796 MSI_SetPropertyW(package, szAction, szInstall);
9cd707da 797
3a94011a 798 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
401bd3f7 799
c9802931
AS
800 package->script->InWhatSequence = SEQUENCE_INSTALL;
801
e95136b7
AS
802 if (szPackagePath)
803 {
c777d309 804 LPWSTR p, dir;
0e14c29d 805 LPCWSTR file;
08443b3b
JH
806
807 dir = strdupW(szPackagePath);
808 p = strrchrW(dir, '\\');
e95136b7 809 if (p)
0e14c29d 810 {
08443b3b 811 *(++p) = 0;
0e14c29d
AT
812 file = szPackagePath + (p - dir);
813 }
08443b3b 814 else
e95136b7 815 {
08443b3b
JH
816 msi_free(dir);
817 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
818 GetCurrentDirectoryW(MAX_PATH, dir);
819 lstrcatW(dir, cszbs);
0e14c29d 820 file = szPackagePath;
e95136b7 821 }
08443b3b
JH
822
823 msi_free( package->PackagePath );
0e14c29d 824 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
08443b3b 825 if (!package->PackagePath)
c1e5c4a9 826 {
08443b3b
JH
827 msi_free(dir);
828 return ERROR_OUTOFMEMORY;
c1e5c4a9 829 }
e95136b7 830
08443b3b 831 lstrcpyW(package->PackagePath, dir);
0e14c29d 832 lstrcatW(package->PackagePath, file);
08443b3b 833 msi_free(dir);
c777d309
JH
834
835 msi_set_sourcedir_props(package, FALSE);
e95136b7 836 }
401bd3f7 837
ca71e5af 838 msi_parse_command_line( package, szCommandLine, FALSE );
74f0de96 839
e534e772 840 msi_apply_transforms( package );
965a72ad
MM
841 msi_apply_patches( package );
842
1169aa9a
HL
843 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
844 {
845 TRACE("setting reinstall property\n");
846 MSI_SetPropertyW( package, szReinstall, szAll );
847 }
848
30fc5602
JH
849 /* properties may have been added by a transform */
850 msi_clone_properties( package );
5f11262d 851 msi_set_context( package );
30fc5602 852
d8b00a07 853 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
ed7c4bc8 854 {
74f0de96
MM
855 package->script->InWhatSequence |= SEQUENCE_UI;
856 rc = ACTION_ProcessUISequence(package);
857 ui = TRUE;
6da8041d
JH
858 ui_exists = ui_sequence_exists(package);
859 if (rc == ERROR_SUCCESS || !ui_exists)
ed7c4bc8 860 {
74f0de96 861 package->script->InWhatSequence |= SEQUENCE_EXEC;
6da8041d 862 rc = ACTION_ProcessExecSequence(package,ui_exists);
ed7c4bc8 863 }
ed7c4bc8
AS
864 }
865 else
a7a6f5f3 866 rc = ACTION_ProcessExecSequence(package,FALSE);
ed7c4bc8 867
9cd707da
AS
868 package->script->CurrentlyScripting= FALSE;
869
09d35c3c
AS
870 /* process the ending type action */
871 if (rc == ERROR_SUCCESS)
f8f64406 872 ACTION_PerformActionSequence(package,-1,ui);
6b16f29f 873 else if (rc == ERROR_INSTALL_USEREXIT)
f8f64406 874 ACTION_PerformActionSequence(package,-2,ui);
6b16f29f 875 else if (rc == ERROR_INSTALL_SUSPEND)
f8f64406 876 ACTION_PerformActionSequence(package,-4,ui);
9cd707da
AS
877 else /* failed */
878 ACTION_PerformActionSequence(package,-3,ui);
54c67dd1
AS
879
880 /* finish up running custom actions */
881 ACTION_FinishCustomActions(package);
09d35c3c 882
9c8b83ce
HL
883 if (rc == ERROR_SUCCESS && package->need_reboot)
884 return ERROR_SUCCESS_REBOOT_REQUIRED;
885
ed7c4bc8
AS
886 return rc;
887}
888
f8f64406 889static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
09d35c3c 890{
0b352c7f 891 UINT rc = ERROR_SUCCESS;
09d35c3c 892 MSIRECORD * row = 0;
8e233e9b
AS
893 static const WCHAR ExecSeqQuery[] =
894 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082
AS
895 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
896 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
897 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
09d35c3c 898
f8f64406
AS
899 static const WCHAR UISeqQuery[] =
900 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082
AS
901 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
902 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
f8f64406
AS
903 ' ', '=',' ','%','i',0};
904
905 if (UI)
0b352c7f 906 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
f8f64406 907 else
0b352c7f 908 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
09d35c3c 909
0b352c7f 910 if (row)
09d35c3c 911 {
20806c73
MM
912 LPCWSTR action, cond;
913
09d35c3c
AS
914 TRACE("Running the actions\n");
915
09d35c3c 916 /* check conditions */
20806c73 917 cond = MSI_RecordGetString(row,2);
9375fd9f
MM
918
919 /* this is a hack to skip errors in the condition code */
920 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
921 goto end;
09d35c3c 922
20806c73
MM
923 action = MSI_RecordGetString(row,1);
924 if (!action)
09d35c3c 925 {
20806c73
MM
926 ERR("failed to fetch action\n");
927 rc = ERROR_FUNCTION_FAILED;
09d35c3c
AS
928 goto end;
929 }
930
f8f64406 931 if (UI)
8a94f7aa 932 rc = ACTION_PerformUIAction(package,action,-1);
f8f64406 933 else
8a94f7aa 934 rc = ACTION_PerformAction(package,action,-1,FALSE);
09d35c3c 935end:
0b352c7f 936 msiobj_release(&row->hdr);
09d35c3c
AS
937 }
938 else
939 rc = ERROR_SUCCESS;
940
941 return rc;
942}
ed7c4bc8 943
2703d717
AS
944typedef struct {
945 MSIPACKAGE* package;
946 BOOL UI;
947} iterate_action_param;
948
949static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
950{
5f3ac30b 951 iterate_action_param *iap = param;
2703d717
AS
952 UINT rc;
953 LPCWSTR cond, action;
954
955 action = MSI_RecordGetString(row,1);
956 if (!action)
957 {
958 ERR("Error is retrieving action name\n");
9375fd9f 959 return ERROR_FUNCTION_FAILED;
2703d717
AS
960 }
961
962 /* check conditions */
963 cond = MSI_RecordGetString(row,2);
9375fd9f
MM
964
965 /* this is a hack to skip errors in the condition code */
966 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
2703d717 967 {
9375fd9f
MM
968 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
969 return ERROR_SUCCESS;
2703d717
AS
970 }
971
972 if (iap->UI)
8a94f7aa 973 rc = ACTION_PerformUIAction(iap->package,action,-1);
2703d717 974 else
8a94f7aa 975 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
2703d717 976
4f634a3b
MM
977 msi_dialog_check_messages( NULL );
978
979 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
980 rc = iap->package->CurrentInstallState;
981
2703d717
AS
982 if (rc == ERROR_FUNCTION_NOT_CALLED)
983 rc = ERROR_SUCCESS;
984
985 if (rc != ERROR_SUCCESS)
558abec8 986 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
2703d717
AS
987
988 return rc;
989}
990
d34b1c23
MM
991UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
992{
993 MSIQUERY * view;
994 UINT r;
995 static const WCHAR query[] =
996 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
997 '`','%','s','`',
998 ' ','W','H','E','R','E',' ',
999 '`','S','e','q','u','e','n','c','e','`',' ',
1000 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1001 '`','S','e','q','u','e','n','c','e','`',0};
1002 iterate_action_param iap;
1003
1004 /*
1005 * FIXME: probably should be checking UILevel in the
1006 * ACTION_PerformUIAction/ACTION_PerformAction
1007 * rather than saving the UI level here. Those
1008 * two functions can be merged too.
1009 */
1010 iap.package = package;
1011 iap.UI = TRUE;
1012
1013 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
1014
1015 r = MSI_OpenQuery( package->db, &view, query, szTable );
1016 if (r == ERROR_SUCCESS)
1017 {
1018 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
1019 msiobj_release(&view->hdr);
1020 }
1021
1022 return r;
1023}
1024
a7a6f5f3 1025static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
ed7c4bc8 1026{
a7a6f5f3 1027 MSIQUERY * view;
ed7c4bc8 1028 UINT rc;
8e233e9b
AS
1029 static const WCHAR ExecSeqQuery[] =
1030 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
98e38082
AS
1031 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1032 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1033 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
8e233e9b 1034 'O','R','D','E','R',' ', 'B','Y',' ',
98e38082 1035 '`','S','e','q','u','e','n','c','e','`',0 };
a7a6f5f3 1036 MSIRECORD * row = 0;
8e233e9b 1037 static const WCHAR IVQuery[] =
98e38082
AS
1038 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1039 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1040 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1041 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1042 ' ','\'', 'I','n','s','t','a','l','l',
1043 'V','a','l','i','d','a','t','e','\'', 0};
9db0e072 1044 INT seq = 0;
2703d717 1045 iterate_action_param iap;
ed7c4bc8 1046
2703d717
AS
1047 iap.package = package;
1048 iap.UI = FALSE;
b6bc6aa6 1049
9cd707da 1050 if (package->script->ExecuteSequenceRun)
b6bc6aa6
AS
1051 {
1052 TRACE("Execute Sequence already Run\n");
1053 return ERROR_SUCCESS;
1054 }
1055
9cd707da 1056 package->script->ExecuteSequenceRun = TRUE;
2703d717 1057
9db0e072 1058 /* get the sequence number */
ed7c4bc8
AS
1059 if (UIran)
1060 {
0b352c7f
MM
1061 row = MSI_QueryGetRecord(package->db, IVQuery);
1062 if( !row )
1063 return ERROR_FUNCTION_FAILED;
a7a6f5f3
AJ
1064 seq = MSI_RecordGetInteger(row,1);
1065 msiobj_release(&row->hdr);
ed7c4bc8 1066 }
9db0e072 1067
0c238856 1068 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
401bd3f7
AS
1069 if (rc == ERROR_SUCCESS)
1070 {
2703d717 1071 TRACE("Running the actions\n");
401bd3f7 1072
2703d717 1073 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
a7a6f5f3 1074 msiobj_release(&view->hdr);
401bd3f7
AS
1075 }
1076
401bd3f7
AS
1077 return rc;
1078}
1079
a7a6f5f3 1080static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
ed7c4bc8 1081{
a7a6f5f3 1082 MSIQUERY * view;
ed7c4bc8 1083 UINT rc;
8e233e9b
AS
1084 static const WCHAR ExecSeqQuery [] =
1085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082
AS
1086 '`','I','n','s','t','a','l','l',
1087 'U','I','S','e','q','u','e','n','c','e','`',
1088 ' ','W','H','E','R','E',' ',
1089 '`','S','e','q','u','e','n','c','e','`',' ',
8e233e9b 1090 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
98e38082 1091 '`','S','e','q','u','e','n','c','e','`',0};
2703d717
AS
1092 iterate_action_param iap;
1093
1094 iap.package = package;
1095 iap.UI = TRUE;
1096
a7a6f5f3 1097 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
ed7c4bc8
AS
1098
1099 if (rc == ERROR_SUCCESS)
1100 {
0edbaf7e 1101 TRACE("Running the actions\n");
ed7c4bc8 1102
2703d717 1103 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
a7a6f5f3 1104 msiobj_release(&view->hdr);
ed7c4bc8
AS
1105 }
1106
ed7c4bc8
AS
1107 return rc;
1108}
1109
401bd3f7
AS
1110/********************************************************
1111 * ACTION helper functions and functions that perform the actions
1112 *******************************************************/
f9acfe63 1113static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
8a94f7aa 1114 UINT* rc, UINT script, BOOL force )
3f318609
AS
1115{
1116 BOOL ret=FALSE;
1117 UINT arc;
1118
8a94f7aa 1119 arc = ACTION_CustomAction(package, action, script, force);
3f318609
AS
1120
1121 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1122 {
1123 *rc = arc;
1124 ret = TRUE;
1125 }
1126 return ret;
1127}
401bd3f7
AS
1128
1129/*
da8b3dd7
FG
1130 * A lot of actions are really important even if they don't do anything
1131 * explicit... Lots of properties are set at the beginning of the installation
1132 * CostFinalize does a bunch of work to translate the directories and such
401bd3f7 1133 *
6e2bca34 1134 * But until I get write access to the database that is hard, so I am going to
401bd3f7
AS
1135 * hack it to see if I can get something to run.
1136 */
8a94f7aa 1137UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
401bd3f7 1138{
d2c395ad 1139 UINT rc = ERROR_SUCCESS;
3f318609 1140 BOOL handled;
401bd3f7
AS
1141
1142 TRACE("Performing action (%s)\n",debugstr_w(action));
7d3e5973 1143
9cd707da 1144 handled = ACTION_HandleStandardAction(package, action, &rc, force);
3f318609
AS
1145
1146 if (!handled)
8a94f7aa 1147 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
3f318609
AS
1148
1149 if (!handled)
90c57396 1150 {
c48daf93 1151 WARN("unhandled msi action %s\n",debugstr_w(action));
3f318609 1152 rc = ERROR_FUNCTION_NOT_CALLED;
90c57396 1153 }
c75201f4 1154
3f318609
AS
1155 return rc;
1156}
1157
8a94f7aa 1158UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
3f318609
AS
1159{
1160 UINT rc = ERROR_SUCCESS;
1161 BOOL handled = FALSE;
1162
1163 TRACE("Performing action (%s)\n",debugstr_w(action));
1164
9cd707da 1165 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
3f318609 1166
90c57396 1167 if (!handled)
8a94f7aa 1168 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
90c57396 1169
4f634a3b
MM
1170 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1171 handled = TRUE;
34d4a02b 1172
3f318609
AS
1173 if (!handled)
1174 {
c48daf93 1175 WARN("unhandled msi action %s\n",debugstr_w(action));
3f318609 1176 rc = ERROR_FUNCTION_NOT_CALLED;
90c57396 1177 }
401bd3f7 1178
d2c395ad 1179 return rc;
401bd3f7
AS
1180}
1181
2274ff19
AS
1182
1183/*
1184 * Actual Action Handlers
1185 */
1186
1187static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1188{
5f3ac30b 1189 MSIPACKAGE *package = param;
2274ff19
AS
1190 LPCWSTR dir;
1191 LPWSTR full_path;
1192 MSIRECORD *uirow;
1193 MSIFOLDER *folder;
1194
1195 dir = MSI_RecordGetString(row,1);
1196 if (!dir)
1197 {
0edbaf7e 1198 ERR("Unable to get folder id\n");
2274ff19
AS
1199 return ERROR_SUCCESS;
1200 }
1201
8cedb218 1202 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
2274ff19
AS
1203 if (!full_path)
1204 {
1205 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1206 return ERROR_SUCCESS;
1207 }
1208
1209 TRACE("Folder is %s\n",debugstr_w(full_path));
1210
1211 /* UI stuff */
1212 uirow = MSI_CreateRecord(1);
1213 MSI_RecordSetStringW(uirow,1,full_path);
1214 ui_actiondata(package,szCreateFolders,uirow);
1215 msiobj_release( &uirow->hdr );
1216
1217 if (folder->State == 0)
1218 create_full_pathW(full_path);
1219
1220 folder->State = 3;
1221
ee034ba4 1222 msi_free(full_path);
2274ff19
AS
1223 return ERROR_SUCCESS;
1224}
1225
03b4dbbd
MM
1226/* FIXME: probably should merge this with the above function */
1227static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1228{
1229 UINT rc = ERROR_SUCCESS;
1230 MSIFOLDER *folder;
1231 LPWSTR install_path;
1232
8cedb218 1233 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
03b4dbbd
MM
1234 if (!install_path)
1235 return ERROR_FUNCTION_FAILED;
1236
1237 /* create the path */
1238 if (folder->State == 0)
1239 {
1240 create_full_pathW(install_path);
1241 folder->State = 2;
1242 }
1243 msi_free(install_path);
1244
1245 return rc;
1246}
2274ff19 1247
9c845851
MM
1248UINT msi_create_component_directories( MSIPACKAGE *package )
1249{
1250 MSICOMPONENT *comp;
1251
1252 /* create all the folders required by the components are going to install */
1253 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1254 {
d693f461 1255 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
9c845851
MM
1256 continue;
1257 msi_create_directory( package, comp->Directory );
1258 }
1259
1260 return ERROR_SUCCESS;
1261}
1262
401bd3f7
AS
1263/*
1264 * Also we cannot enable/disable components either, so for now I am just going
6e2bca34 1265 * to do all the directories for all the components.
401bd3f7 1266 */
a7a6f5f3 1267static UINT ACTION_CreateFolders(MSIPACKAGE *package)
401bd3f7 1268{
8e233e9b 1269 static const WCHAR ExecSeqQuery[] =
98e38082
AS
1270 {'S','E','L','E','C','T',' ',
1271 '`','D','i','r','e','c','t','o','r','y','_','`',
8e233e9b 1272 ' ','F','R','O','M',' ',
98e38082 1273 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
401bd3f7 1274 UINT rc;
a7a6f5f3 1275 MSIQUERY *view;
eb0e0df9 1276
03b4dbbd 1277 /* create all the empty folders specified in the CreateFolder table */
a7a6f5f3 1278 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
401bd3f7 1279 if (rc != ERROR_SUCCESS)
84837d96 1280 return ERROR_SUCCESS;
401bd3f7 1281
2274ff19 1282 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
a7a6f5f3 1283 msiobj_release(&view->hdr);
03b4dbbd 1284
9c845851 1285 msi_create_component_directories( package );
03b4dbbd 1286
401bd3f7
AS
1287 return rc;
1288}
1289
1d46cdf1 1290static UINT load_component( MSIRECORD *row, LPVOID param )
bdb29552 1291{
1d46cdf1 1292 MSIPACKAGE *package = param;
38d67a45 1293 MSICOMPONENT *comp;
bdb29552 1294
ee034ba4 1295 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
38d67a45 1296 if (!comp)
1d46cdf1
MM
1297 return ERROR_FUNCTION_FAILED;
1298
1299 list_add_tail( &package->components, &comp->entry );
bdb29552 1300
38d67a45 1301 /* fill in the data */
51c6618d 1302 comp->Component = msi_dup_record_field( row, 1 );
bdb29552 1303
efcc1ec5 1304 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
bdb29552 1305
51c6618d
MM
1306 comp->ComponentId = msi_dup_record_field( row, 2 );
1307 comp->Directory = msi_dup_record_field( row, 3 );
38d67a45 1308 comp->Attributes = MSI_RecordGetInteger(row,4);
51c6618d
MM
1309 comp->Condition = msi_dup_record_field( row, 5 );
1310 comp->KeyPath = msi_dup_record_field( row, 6 );
bdb29552 1311
d893cb7d 1312 comp->Installed = INSTALLSTATE_UNKNOWN;
3bec162d 1313 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
fbdd7096 1314
1d46cdf1
MM
1315 return ERROR_SUCCESS;
1316}
1317
1318static UINT load_all_components( MSIPACKAGE *package )
1319{
1320 static const WCHAR query[] = {
1321 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1322 '`','C','o','m','p','o','n','e','n','t','`',0 };
1323 MSIQUERY *view;
1324 UINT r;
1325
1326 if (!list_empty(&package->components))
1327 return ERROR_SUCCESS;
bdb29552 1328
1d46cdf1
MM
1329 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1330 if (r != ERROR_SUCCESS)
1331 return r;
1332
1333 r = MSI_IterateRecords(view, NULL, load_component, package);
1334 msiobj_release(&view->hdr);
1335 return r;
bdb29552
AS
1336}
1337
04598248
AS
1338typedef struct {
1339 MSIPACKAGE *package;
1da2858c 1340 MSIFEATURE *feature;
04598248
AS
1341} _ilfs;
1342
38d67a45 1343static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
3f2d5d7f
MM
1344{
1345 ComponentList *cl;
1346
ee034ba4 1347 cl = msi_alloc( sizeof (*cl) );
3f2d5d7f
MM
1348 if ( !cl )
1349 return ERROR_NOT_ENOUGH_MEMORY;
38d67a45 1350 cl->component = comp;
1da2858c 1351 list_add_tail( &feature->Components, &cl->entry );
3f2d5d7f
MM
1352
1353 return ERROR_SUCCESS;
1354}
1355
545d0e70
JH
1356static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1357{
1358 FeatureList *fl;
1359
1360 fl = msi_alloc( sizeof(*fl) );
1361 if ( !fl )
1362 return ERROR_NOT_ENOUGH_MEMORY;
1363 fl->feature = child;
1364 list_add_tail( &parent->Children, &fl->entry );
1365
1366 return ERROR_SUCCESS;
1367}
1368
04598248 1369static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
bdb29552 1370{
5f3ac30b 1371 _ilfs* ilfs = param;
04598248 1372 LPCWSTR component;
38d67a45 1373 MSICOMPONENT *comp;
04598248
AS
1374
1375 component = MSI_RecordGetString(row,1);
1376
1377 /* check to see if the component is already loaded */
38d67a45 1378 comp = get_loaded_component( ilfs->package, component );
1d46cdf1 1379 if (!comp)
04598248 1380 {
1d46cdf1
MM
1381 ERR("unknown component %s\n", debugstr_w(component));
1382 return ERROR_FUNCTION_FAILED;
04598248
AS
1383 }
1384
1d46cdf1
MM
1385 add_feature_component( ilfs->feature, comp );
1386 comp->Enabled = TRUE;
04598248
AS
1387
1388 return ERROR_SUCCESS;
1389}
1390
545d0e70
JH
1391static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1392{
1393 MSIFEATURE *feature;
1394
bfe07d1d
JH
1395 if ( !name )
1396 return NULL;
1397
545d0e70
JH
1398 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1399 {
1400 if ( !lstrcmpW( feature->Feature, name ) )
1401 return feature;
1402 }
1403
1404 return NULL;
1405}
1406
04598248
AS
1407static UINT load_feature(MSIRECORD * row, LPVOID param)
1408{
5f3ac30b 1409 MSIPACKAGE* package = param;
1da2858c 1410 MSIFEATURE* feature;
8e233e9b 1411 static const WCHAR Query1[] =
98e38082
AS
1412 {'S','E','L','E','C','T',' ',
1413 '`','C','o','m','p','o','n','e','n','t','_','`',
1414 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1415 'C','o','m','p','o','n','e','n','t','s','`',' ',
1416 'W','H','E','R','E',' ',
1417 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
a7a6f5f3 1418 MSIQUERY * view;
a7a6f5f3 1419 UINT rc;
04598248
AS
1420 _ilfs ilfs;
1421
bdb29552
AS
1422 /* fill in the data */
1423
ee034ba4 1424 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1da2858c
MM
1425 if (!feature)
1426 return ERROR_NOT_ENOUGH_MEMORY;
3f2d5d7f 1427
545d0e70 1428 list_init( &feature->Children );
1da2858c 1429 list_init( &feature->Components );
bdb29552 1430
51c6618d 1431 feature->Feature = msi_dup_record_field( row, 1 );
bdb29552 1432
1da2858c 1433 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
bdb29552 1434
51c6618d
MM
1435 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1436 feature->Title = msi_dup_record_field( row, 3 );
1437 feature->Description = msi_dup_record_field( row, 4 );
bdb29552 1438
a7a6f5f3 1439 if (!MSI_RecordIsNull(row,5))
1da2858c 1440 feature->Display = MSI_RecordGetInteger(row,5);
bdb29552 1441
1da2858c 1442 feature->Level= MSI_RecordGetInteger(row,6);
51c6618d 1443 feature->Directory = msi_dup_record_field( row, 7 );
1da2858c 1444 feature->Attributes = MSI_RecordGetInteger(row,8);
bdb29552 1445
ca5c1100 1446 feature->Installed = INSTALLSTATE_UNKNOWN;
d596ae29 1447 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
fbdd7096 1448
1da2858c 1449 list_add_tail( &package->features, &feature->entry );
bdb29552
AS
1450
1451 /* load feature components */
1452
1da2858c 1453 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
a7a6f5f3 1454 if (rc != ERROR_SUCCESS)
04598248 1455 return ERROR_SUCCESS;
bdb29552 1456
1da2858c
MM
1457 ilfs.package = package;
1458 ilfs.feature = feature;
1459
04598248 1460 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
a7a6f5f3 1461 msiobj_release(&view->hdr);
04598248
AS
1462
1463 return ERROR_SUCCESS;
bdb29552
AS
1464}
1465
545d0e70
JH
1466static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1467{
5f3ac30b 1468 MSIPACKAGE* package = param;
545d0e70
JH
1469 MSIFEATURE *parent, *child;
1470
1471 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1472 if (!child)
1473 return ERROR_FUNCTION_FAILED;
1474
1475 if (!child->Feature_Parent)
1476 return ERROR_SUCCESS;
1477
1478 parent = find_feature_by_name( package, child->Feature_Parent );
1479 if (!parent)
1480 return ERROR_FUNCTION_FAILED;
1481
1482 add_feature_child( parent, child );
1483 return ERROR_SUCCESS;
1484}
1485
1d46cdf1
MM
1486static UINT load_all_features( MSIPACKAGE *package )
1487{
1488 static const WCHAR query[] = {
1489 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1490 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1491 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1492 MSIQUERY *view;
1493 UINT r;
1494
1495 if (!list_empty(&package->features))
1496 return ERROR_SUCCESS;
1497
1498 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1499 if (r != ERROR_SUCCESS)
1500 return r;
1501
1502 r = MSI_IterateRecords( view, NULL, load_feature, package );
545d0e70
JH
1503 if (r != ERROR_SUCCESS)
1504 return r;
1505
1506 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1d46cdf1 1507 msiobj_release( &view->hdr );
545d0e70 1508
1d46cdf1
MM
1509 return r;
1510}
1511
c1513be4
MM
1512static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1513{
1514 if (!p)
1515 return p;
1516 p = strchrW(p, ch);
1517 if (!p)
1518 return p;
1519 *p = 0;
1520 return p+1;
1521}
1522
4160722b
JH
1523static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1524{
1525 static const WCHAR query[] = {
1526 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1527 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1528 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1529 MSIQUERY *view = NULL;
1277e1b5 1530 MSIRECORD *row = NULL;
4160722b
JH
1531 UINT r;
1532
1533 TRACE("%s\n", debugstr_w(file->File));
1534
1535 r = MSI_OpenQuery(package->db, &view, query, file->File);
1536 if (r != ERROR_SUCCESS)
1537 goto done;
1538
1539 r = MSI_ViewExecute(view, NULL);
1540 if (r != ERROR_SUCCESS)
1541 goto done;
1542
1543 r = MSI_ViewFetch(view, &row);
1544 if (r != ERROR_SUCCESS)
1545 goto done;
1546
1547 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1548 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1549 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1550 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1551 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1552
1553done:
1554 if (view) msiobj_release(&view->hdr);
1277e1b5 1555 if (row) msiobj_release(&row->hdr);
4160722b
JH
1556 return r;
1557}
1558
04598248 1559static UINT load_file(MSIRECORD *row, LPVOID param)
ec688fb4 1560{
5f3ac30b 1561 MSIPACKAGE* package = param;
09b0abaa 1562 LPCWSTR component;
e18f8abe 1563 MSIFILE *file;
ec688fb4
AS
1564
1565 /* fill in the data */
1566
ee034ba4 1567 file = msi_alloc_zero( sizeof (MSIFILE) );
e18f8abe
MM
1568 if (!file)
1569 return ERROR_NOT_ENOUGH_MEMORY;
9db0e072 1570
51c6618d 1571 file->File = msi_dup_record_field( row, 1 );
ec688fb4 1572
e18f8abe
MM
1573 component = MSI_RecordGetString( row, 2 );
1574 file->Component = get_loaded_component( package, component );
09b0abaa 1575
e18f8abe 1576 if (!file->Component)
9a8d2f3f
JH
1577 {
1578 WARN("Component not found: %s\n", debugstr_w(component));
1579 msi_free(file->File);
1580 msi_free(file);
1581 return ERROR_SUCCESS;
1582 }
bdb29552 1583
51c6618d 1584 file->FileName = msi_dup_record_field( row, 3 );
e18f8abe 1585 reduce_to_longfilename( file->FileName );
98d9cec7 1586
51c6618d 1587 file->ShortName = msi_dup_record_field( row, 3 );
c1513be4 1588 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
ec688fb4 1589
e18f8abe 1590 file->FileSize = MSI_RecordGetInteger( row, 4 );
51c6618d
MM
1591 file->Version = msi_dup_record_field( row, 5 );
1592 file->Language = msi_dup_record_field( row, 6 );
e18f8abe
MM
1593 file->Attributes = MSI_RecordGetInteger( row, 7 );
1594 file->Sequence = MSI_RecordGetInteger( row, 8 );
1595
dded8fb7 1596 file->state = msifs_invalid;
ec688fb4 1597
f84fa0ce
JH
1598 /* if the compressed bits are not set in the file attributes,
1599 * then read the information from the package word count property
1600 */
f80b5f6e
JH
1601 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1602 {
1603 file->IsCompressed = FALSE;
1604 }
1605 else if (file->Attributes &
1606 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
f84fa0ce
JH
1607 {
1608 file->IsCompressed = TRUE;
1609 }
1610 else if (file->Attributes & msidbFileAttributesNoncompressed)
1611 {
1612 file->IsCompressed = FALSE;
1613 }
1614 else
1615 {
7538f9ac 1616 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
f84fa0ce
JH
1617 }
1618
4160722b
JH
1619 load_file_hash(package, file);
1620
e18f8abe 1621 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
ec688fb4 1622
e18f8abe 1623 list_add_tail( &package->files, &file->entry );
ec688fb4
AS
1624
1625 return ERROR_SUCCESS;
1626}
1627
c5a1443f 1628static UINT load_all_files(MSIPACKAGE *package)
ec688fb4 1629{
a7a6f5f3 1630 MSIQUERY * view;
ec688fb4 1631 UINT rc;
8e233e9b
AS
1632 static const WCHAR Query[] =
1633 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
98e38082
AS
1634 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1635 '`','S','e','q','u','e','n','c','e','`', 0};
ec688fb4 1636
9a9195d6
MM
1637 if (!list_empty(&package->files))
1638 return ERROR_SUCCESS;
1639
a7a6f5f3 1640 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
ec688fb4 1641 if (rc != ERROR_SUCCESS)
84837d96 1642 return ERROR_SUCCESS;
ec688fb4 1643
04598248 1644 rc = MSI_IterateRecords(view, NULL, load_file, package);
a7a6f5f3 1645 msiobj_release(&view->hdr);
bdb29552
AS
1646
1647 return ERROR_SUCCESS;
1648}
1649
7eb27026
MM
1650static UINT load_folder( MSIRECORD *row, LPVOID param )
1651{
1652 MSIPACKAGE *package = param;
1653 static const WCHAR szDot[] = { '.',0 };
1654 static WCHAR szEmpty[] = { 0 };
1655 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1656 MSIFOLDER *folder;
1657
1658 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1659 if (!folder)
1660 return ERROR_NOT_ENOUGH_MEMORY;
1661
1662 folder->Directory = msi_dup_record_field( row, 1 );
1663
1664 TRACE("%s\n", debugstr_w(folder->Directory));
1665
1666 p = msi_dup_record_field(row, 3);
1667
1668 /* split src and target dir */
1669 tgt_short = p;
1670 src_short = folder_split_path( p, ':' );
1671
1672 /* split the long and short paths */
1673 tgt_long = folder_split_path( tgt_short, '|' );
1674 src_long = folder_split_path( src_short, '|' );
1675
1676 /* check for no-op dirs */
1677 if (!lstrcmpW(szDot, tgt_short))
1678 tgt_short = szEmpty;
1679 if (!lstrcmpW(szDot, src_short))
1680 src_short = szEmpty;
1681
1682 if (!tgt_long)
1683 tgt_long = tgt_short;
1684
1685 if (!src_short) {
1686 src_short = tgt_short;
1687 src_long = tgt_long;
1688 }
1689
1690 if (!src_long)
1691 src_long = src_short;
1692
1693 /* FIXME: use the target short path too */
1694 folder->TargetDefault = strdupW(tgt_long);
1695 folder->SourceShortPath = strdupW(src_short);
1696 folder->SourceLongPath = strdupW(src_long);
1697 msi_free(p);
1698
1699 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1700 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1701 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1702
1703 folder->Parent = msi_dup_record_field( row, 2 );
1704
1705 folder->Property = msi_dup_property( package, folder->Directory );
1706
1707 list_add_tail( &package->folders, &folder->entry );
1708
1709 TRACE("returning %p\n", folder);
1710
1711 return ERROR_SUCCESS;
1712}
1713
1714static UINT load_all_folders( MSIPACKAGE *package )
1715{
1716 static const WCHAR query[] = {
1717 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1718 '`','D','i','r','e','c','t','o','r','y','`',0 };
1719 MSIQUERY *view;
1720 UINT r;
1721
1722 if (!list_empty(&package->folders))
1723 return ERROR_SUCCESS;
1724
1725 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1726 if (r != ERROR_SUCCESS)
1727 return r;
1728
1729 r = MSI_IterateRecords(view, NULL, load_folder, package);
1730 msiobj_release(&view->hdr);
1731 return r;
1732}
c5a1443f
AS
1733
1734/*
9a9195d6 1735 * I am not doing any of the costing functionality yet.
c5a1443f
AS
1736 * Mostly looking at doing the Component and Feature loading
1737 *
1738 * The native MSI does A LOT of modification to tables here. Mostly adding
9a9195d6 1739 * a lot of temporary columns to the Feature and Component tables.
c5a1443f
AS
1740 *
1741 * note: Native msi also tracks the short filename. But I am only going to
1742 * track the long ones. Also looking at this directory table
1743 * it appears that the directory table does not get the parents
9a9195d6 1744 * resolved base on property only based on their entries in the
c5a1443f
AS
1745 * directory table.
1746 */
1747static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1748{
c5a1443f
AS
1749 static const WCHAR szCosting[] =
1750 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1751 static const WCHAR szZero[] = { '0', 0 };
c5a1443f 1752
c5a1443f 1753 MSI_SetPropertyW(package, szCosting, szZero);
1d46cdf1 1754 MSI_SetPropertyW(package, cszRootDrive, c_colon);
c5a1443f 1755
dbbd5ca7 1756 load_all_folders( package );
1d46cdf1
MM
1757 load_all_components( package );
1758 load_all_features( package );
1759 load_all_files( package );
c5a1443f
AS
1760
1761 return ERROR_SUCCESS;
1762}
1763
f9acfe63 1764static UINT execute_script(MSIPACKAGE *package, UINT script )
9cd707da 1765{
bb54ed13 1766 UINT i;
9cd707da
AS
1767 UINT rc = ERROR_SUCCESS;
1768
1769 TRACE("Executing Script %i\n",script);
1770
aa81e4fa
MM
1771 if (!package->script)
1772 {
1773 ERR("no script!\n");
1774 return ERROR_FUNCTION_FAILED;
1775 }
1776
9cd707da
AS
1777 for (i = 0; i < package->script->ActionCount[script]; i++)
1778 {
1779 LPWSTR action;
1780 action = package->script->Actions[script][i];
1781 ui_actionstart(package, action);
1782 TRACE("Executing Action (%s)\n",debugstr_w(action));
8a94f7aa 1783 rc = ACTION_PerformAction(package, action, script, TRUE);
9cd707da
AS
1784 if (rc != ERROR_SUCCESS)
1785 break;
1786 }
f86cfd40 1787 msi_free_action_script(package, script);
9cd707da
AS
1788 return rc;
1789}
1790
c5a1443f
AS
1791static UINT ACTION_FileCost(MSIPACKAGE *package)
1792{
1793 return ERROR_SUCCESS;
1794}
1795
b7669153 1796static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
78a04e39 1797{
38d67a45 1798 MSICOMPONENT *comp;
42115638
JH
1799 INSTALLSTATE state;
1800 UINT r;
78a04e39 1801
42115638 1802 state = MsiQueryProductStateW(package->ProductCode);
32f57022 1803
42115638
JH
1804 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1805 {
32f57022
JH
1806 if (!comp->ComponentId)
1807 continue;
1808
42115638
JH
1809 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1810 comp->Installed = INSTALLSTATE_ABSENT;
1811 else
1812 {
1813 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1814 package->Context, comp->ComponentId,
1815 &comp->Installed);
1816 if (r != ERROR_SUCCESS)
1817 comp->Installed = INSTALLSTATE_ABSENT;
1818 }
78a04e39 1819 }
b7669153
MM
1820}
1821
5a3c3b6a 1822static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
b7669153 1823{
b7669153 1824 MSIFEATURE *feature;
5a3c3b6a
JH
1825 INSTALLSTATE state;
1826
1827 state = MsiQueryProductStateW(package->ProductCode);
78a04e39 1828
1da2858c 1829 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
78a04e39 1830 {
5a3c3b6a
JH
1831 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1832 feature->Installed = INSTALLSTATE_ABSENT;
1833 else
78a04e39 1834 {
5a3c3b6a
JH
1835 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1836 feature->Feature);
78a04e39
AS
1837 }
1838 }
1839}
1840
c855fbfc
JH
1841static BOOL process_state_property(MSIPACKAGE* package, int level,
1842 LPCWSTR property, INSTALLSTATE state)
ae1aa32c 1843{
ae1aa32c 1844 static const WCHAR all[]={'A','L','L',0};
c855fbfc 1845 static const WCHAR remove[] = {'R','E','M','O','V','E',0};
40cfbaf0 1846 static const WCHAR reinstall[] = {'R','E','I','N','S','T','A','L','L',0};
72faac0d 1847 LPWSTR override;
1da2858c 1848 MSIFEATURE *feature;
ae1aa32c 1849
062ad505 1850 override = msi_dup_property( package, property );
72faac0d
MM
1851 if (!override)
1852 return FALSE;
575cc67d 1853
72faac0d 1854 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
ae1aa32c 1855 {
c855fbfc
JH
1856 if (lstrcmpW(property, remove) &&
1857 (feature->Level <= 0 || feature->Level > level))
1858 continue;
1859
40cfbaf0
HL
1860 if (!strcmpW(property, reinstall)) state = feature->Installed;
1861
72faac0d 1862 if (strcmpiW(override,all)==0)
d596ae29 1863 msi_feature_set_state(package, feature, state);
72faac0d
MM
1864 else
1865 {
1866 LPWSTR ptr = override;
1867 LPWSTR ptr2 = strchrW(override,',');
d900b539 1868
72faac0d
MM
1869 while (ptr)
1870 {
1871 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1872 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
d900b539 1873 {
d596ae29 1874 msi_feature_set_state(package, feature, state);
72faac0d 1875 break;
d900b539 1876 }
72faac0d
MM
1877 if (ptr2)
1878 {
1879 ptr=ptr2+1;
1880 ptr2 = strchrW(ptr,',');
1881 }
1882 else
1883 break;
d900b539 1884 }
fbdd7096 1885 }
6395ff6a 1886 }
ee034ba4 1887 msi_free(override);
78a04e39 1888
72faac0d 1889 return TRUE;
78a04e39
AS
1890}
1891
7bcac31d 1892UINT MSI_SetFeatureStates(MSIPACKAGE *package)
78a04e39 1893{
c855fbfc 1894 int level;
8e233e9b
AS
1895 static const WCHAR szlevel[] =
1896 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1897 static const WCHAR szAddLocal[] =
1898 {'A','D','D','L','O','C','A','L',0};
c31fd437
JH
1899 static const WCHAR szAddSource[] =
1900 {'A','D','D','S','O','U','R','C','E',0};
8e233e9b
AS
1901 static const WCHAR szRemove[] =
1902 {'R','E','M','O','V','E',0};
d5655f90
AS
1903 static const WCHAR szReinstall[] =
1904 {'R','E','I','N','S','T','A','L','L',0};
4da865f3
HL
1905 static const WCHAR szAdvertise[] =
1906 {'A','D','V','E','R','T','I','S','E',0};
78a04e39 1907 BOOL override = FALSE;
38d67a45 1908 MSICOMPONENT* component;
1da2858c
MM
1909 MSIFEATURE *feature;
1910
78a04e39
AS
1911
1912 /* I do not know if this is where it should happen.. but */
1913
1914 TRACE("Checking Install Level\n");
1915
c855fbfc 1916 level = msi_get_property_int(package, szlevel, 1);
78a04e39 1917
58162f87 1918 /* ok here is the _real_ rub
fbb33435
FG
1919 * all these activation/deactivation things happen in order and things
1920 * later on the list override things earlier on the list.
4da865f3
HL
1921 * 0) INSTALLLEVEL processing
1922 * 1) ADDLOCAL
1923 * 2) REMOVE
1924 * 3) ADDSOURCE
1925 * 4) ADDDEFAULT
1926 * 5) REINSTALL
1927 * 6) ADVERTISE
78a04e39
AS
1928 * 7) COMPADDLOCAL
1929 * 8) COMPADDSOURCE
1930 * 9) FILEADDLOCAL
1931 * 10) FILEADDSOURCE
1932 * 11) FILEADDDEFAULT
78a04e39 1933 *
fbb33435
FG
1934 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1935 * REMOVE are the big ones, since we don't handle administrative installs
1936 * yet anyway.
78a04e39 1937 */
c855fbfc
JH
1938 override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1939 override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1940 override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
40cfbaf0 1941 override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
4da865f3 1942 override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
78a04e39
AS
1943
1944 if (!override)
fbdd7096 1945 {
1da2858c 1946 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
fbdd7096 1947 {
1da2858c 1948 BOOL feature_state = ((feature->Level > 0) &&
c855fbfc 1949 (feature->Level <= level));
ae1aa32c 1950
1da2858c 1951 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
fbdd7096 1952 {
1da2858c 1953 if (feature->Attributes & msidbFeatureAttributesFavorSource)
d596ae29 1954 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1da2858c 1955 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
d596ae29 1956 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
b39d8fc2 1957 else
d596ae29 1958 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
fbdd7096 1959 }
ae1aa32c 1960 }
545d0e70
JH
1961
1962 /* disable child features of unselected parent features */
1963 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1964 {
1965 FeatureList *fl;
1966
c855fbfc 1967 if (feature->Level > 0 && feature->Level <= level)
545d0e70
JH
1968 continue;
1969
1970 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
d596ae29 1971 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
545d0e70 1972 }
fbdd7096 1973 }
6999a042
AS
1974 else
1975 {
1976 /* set the Preselected Property */
1977 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1978 static const WCHAR szOne[] = { '1', 0 };
1979
1980 MSI_SetPropertyW(package,szPreselected,szOne);
1981 }
fbdd7096
AS
1982
1983 /*
6395ff6a
MM
1984 * now we want to enable or disable components base on feature
1985 */
fbdd7096 1986
1da2858c 1987 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
fbdd7096 1988 {
3f2d5d7f
MM
1989 ComponentList *cl;
1990
62219754
JH
1991 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1992 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1993
1994 if (!feature->Level)
1995 continue;
97419aea
MM
1996
1997 /* features with components that have compressed files are made local */
1998 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1999 {
2000 if (cl->component->Enabled &&
2001 cl->component->ForceLocalState &&
2002 feature->Action == INSTALLSTATE_SOURCE)
2003 {
d596ae29 2004 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
97419aea
MM
2005 break;
2006 }
2007 }
ae1aa32c 2008
1da2858c 2009 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
ae1aa32c 2010 {
38d67a45 2011 component = cl->component;
fbdd7096 2012
87fa854d
MM
2013 if (!component->Enabled)
2014 continue;
2015
97419aea 2016 switch (feature->Action)
ad80eceb 2017 {
fc6b9dd4
JH
2018 case INSTALLSTATE_ABSENT:
2019 component->anyAbsent = 1;
2020 break;
97419aea
MM
2021 case INSTALLSTATE_ADVERTISED:
2022 component->hasAdvertiseFeature = 1;
2023 break;
2024 case INSTALLSTATE_SOURCE:
2025 component->hasSourceFeature = 1;
2026 break;
2027 case INSTALLSTATE_LOCAL:
2028 component->hasLocalFeature = 1;
2029 break;
2030 case INSTALLSTATE_DEFAULT:
2031 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
2032 component->hasAdvertiseFeature = 1;
2033 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
2034 component->hasSourceFeature = 1;
ad80eceb 2035 else
97419aea
MM
2036 component->hasLocalFeature = 1;
2037 break;
2038 default:
2039 break;
929395c0 2040 }
97419aea
MM
2041 }
2042 }
929395c0 2043
97419aea
MM
2044 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
2045 {
2046 /* if the component isn't enabled, leave it alone */
2047 if (!component->Enabled)
2048 continue;
2049
2050 /* check if it's local or source */
2051 if (!(component->Attributes & msidbComponentAttributesOptional) &&
2052 (component->hasLocalFeature || component->hasSourceFeature))
2053 {
2054 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
2055 !component->ForceLocalState)
3bec162d 2056 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
97419aea 2057 else
3bec162d 2058 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
97419aea
MM
2059 continue;
2060 }
929395c0 2061
97419aea
MM
2062 /* if any feature is local, the component must be local too */
2063 if (component->hasLocalFeature)
2064 {
3bec162d 2065 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
97419aea
MM
2066 continue;
2067 }
6395ff6a 2068
97419aea
MM
2069 if (component->hasSourceFeature)
2070 {
3bec162d 2071 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
97419aea 2072 continue;
ae1aa32c 2073 }
97419aea
MM
2074
2075 if (component->hasAdvertiseFeature)
2076 {
3bec162d 2077 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
97419aea
MM
2078 continue;
2079 }
2080
2081 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
fc6b9dd4 2082 if (component->anyAbsent)
3bec162d 2083 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
6395ff6a 2084 }
fbdd7096 2085
38d67a45 2086 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
fbdd7096 2087 {
9efb7b71
MM
2088 if (component->Action == INSTALLSTATE_DEFAULT)
2089 {
2090 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
3bec162d 2091 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
9efb7b71
MM
2092 }
2093
3fe6a5d0
MM
2094 TRACE("Result: Component %s (Installed %i, Action %i)\n",
2095 debugstr_w(component->Component), component->Installed, component->Action);
fbdd7096
AS
2096 }
2097
2098
ae1aa32c
AS
2099 return ERROR_SUCCESS;
2100}
2101
443ad4d3
AS
2102static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2103{
5f3ac30b 2104 MSIPACKAGE *package = param;
443ad4d3
AS
2105 LPCWSTR name;
2106 LPWSTR path;
baad8887 2107 MSIFOLDER *f;
443ad4d3
AS
2108
2109 name = MSI_RecordGetString(row,1);
2110
baad8887
JH
2111 f = get_loaded_folder(package, name);
2112 if (!f) return ERROR_SUCCESS;
2113
2114 /* reset the ResolvedTarget */
2115 msi_free(f->ResolvedTarget);
2116 f->ResolvedTarget = NULL;
2117
443ad4d3
AS
2118 /* This helper function now does ALL the work */
2119 TRACE("Dir %s ...\n",debugstr_w(name));
8cedb218 2120 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
443ad4d3 2121 TRACE("resolves to %s\n",debugstr_w(path));
ee034ba4 2122 msi_free(path);
443ad4d3
AS
2123
2124 return ERROR_SUCCESS;
2125}
2126
2127static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2128{
5f3ac30b 2129 MSIPACKAGE *package = param;
1da2858c
MM
2130 LPCWSTR name;
2131 MSIFEATURE *feature;
443ad4d3 2132
1da2858c 2133 name = MSI_RecordGetString( row, 1 );
443ad4d3 2134
1da2858c
MM
2135 feature = get_loaded_feature( package, name );
2136 if (!feature)
2137 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
443ad4d3
AS
2138 else
2139 {
2140 LPCWSTR Condition;
2141 Condition = MSI_RecordGetString(row,3);
2142
0713f098 2143 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
443ad4d3
AS
2144 {
2145 int level = MSI_RecordGetInteger(row,2);
633ee950 2146 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1da2858c 2147 feature->Level = level;
443ad4d3
AS
2148 }
2149 }
2150 return ERROR_SUCCESS;
2151}
2152
020bda7e 2153static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
d1723de5
MM
2154{
2155 static const WCHAR name_fmt[] =
2156 {'%','u','.','%','u','.','%','u','.','%','u',0};
76d6b767 2157 static const WCHAR name[] = {'\\',0};
d1723de5
MM
2158 VS_FIXEDFILEINFO *lpVer;
2159 WCHAR filever[0x100];
2160 LPVOID version;
2161 DWORD versize;
2162 DWORD handle;
2163 UINT sz;
2164
2165 TRACE("%s\n", debugstr_w(filename));
2166
2167 versize = GetFileVersionInfoSizeW( filename, &handle );
2168 if (!versize)
2169 return NULL;
2170
2171 version = msi_alloc( versize );
2172 GetFileVersionInfoW( filename, 0, versize, version );
2173
9c6fac65
RS
2174 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2175 {
2176 msi_free( version );
2177 return NULL;
2178 }
d1723de5
MM
2179
2180 sprintfW( filever, name_fmt,
2181 HIWORD(lpVer->dwFileVersionMS),
2182 LOWORD(lpVer->dwFileVersionMS),
2183 HIWORD(lpVer->dwFileVersionLS),
2184 LOWORD(lpVer->dwFileVersionLS));
2185
023383af
RS
2186 msi_free( version );
2187
d1723de5
MM
2188 return strdupW( filever );
2189}
2190
c5c55210 2191static UINT msi_check_file_install_states( MSIPACKAGE *package )
401bd3f7 2192{
c5c55210 2193 LPWSTR file_version;
e18f8abe 2194 MSIFILE *file;
ec688fb4 2195
e18f8abe 2196 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
ec688fb4 2197 {
f11c8b00
MM
2198 MSICOMPONENT* comp = file->Component;
2199 LPWSTR p;
ec688fb4 2200
f11c8b00
MM
2201 if (!comp)
2202 continue;
ec688fb4 2203
d893cb7d 2204 if (file->IsCompressed)
d893cb7d 2205 comp->ForceLocalState = TRUE;
d893cb7d 2206
f11c8b00 2207 /* calculate target */
8cedb218 2208 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
ba8200bf 2209
ee034ba4 2210 msi_free(file->TargetPath);
fa384f6b 2211
f11c8b00 2212 TRACE("file %s is named %s\n",
d1723de5 2213 debugstr_w(file->File), debugstr_w(file->FileName));
fa384f6b 2214
f11c8b00 2215 file->TargetPath = build_directory_name(2, p, file->FileName);
fa384f6b 2216
ee034ba4 2217 msi_free(p);
ec688fb4 2218
f11c8b00 2219 TRACE("file %s resolves to %s\n",
d1723de5 2220 debugstr_w(file->File), debugstr_w(file->TargetPath));
fa384f6b 2221
ddf0b593
MM
2222 /* don't check files of components that aren't installed */
2223 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2224 comp->Installed == INSTALLSTATE_ABSENT)
2225 {
2226 file->state = msifs_missing; /* assume files are missing */
2227 continue;
2228 }
2229
f11c8b00
MM
2230 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2231 {
dded8fb7 2232 file->state = msifs_missing;
f11c8b00
MM
2233 comp->Cost += file->FileSize;
2234 continue;
2235 }
fa384f6b 2236
d1723de5
MM
2237 if (file->Version &&
2238 (file_version = msi_get_disk_file_version( file->TargetPath )))
f11c8b00 2239 {
f11c8b00 2240 TRACE("new %s old %s\n", debugstr_w(file->Version),
d1723de5
MM
2241 debugstr_w(file_version));
2242 /* FIXME: seems like a bad way to compare version numbers */
2243 if (lstrcmpiW(file_version, file->Version)<0)
ec688fb4 2244 {
dded8fb7 2245 file->state = msifs_overwrite;
ec688fb4
AS
2246 comp->Cost += file->FileSize;
2247 }
2248 else
dded8fb7 2249 file->state = msifs_present;
d1723de5 2250 msi_free( file_version );
f11c8b00
MM
2251 }
2252 else
dded8fb7 2253 file->state = msifs_present;
ec688fb4
AS
2254 }
2255
c5c55210
MM
2256 return ERROR_SUCCESS;
2257}
2258
2259/*
2260 * A lot is done in this function aside from just the costing.
2261 * The costing needs to be implemented at some point but for now I am going
2262 * to focus on the directory building
2263 *
2264 */
2265static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2266{
2267 static const WCHAR ExecSeqQuery[] =
2268 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2269 '`','D','i','r','e','c','t','o','r','y','`',0};
2270 static const WCHAR ConditionQuery[] =
2271 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2272 '`','C','o','n','d','i','t','i','o','n','`',0};
2273 static const WCHAR szCosting[] =
2274 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2275 static const WCHAR szlevel[] =
2276 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
ece5a047
JH
2277 static const WCHAR szOutOfDiskSpace[] =
2278 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
c5c55210 2279 static const WCHAR szOne[] = { '1', 0 };
ece5a047 2280 static const WCHAR szZero[] = { '0', 0 };
c5c55210
MM
2281 MSICOMPONENT *comp;
2282 UINT rc;
2283 MSIQUERY * view;
2284 LPWSTR level;
2285
c5c55210
MM
2286 TRACE("Building Directory properties\n");
2287
2288 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2289 if (rc == ERROR_SUCCESS)
2290 {
2291 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2292 package);
2293 msiobj_release(&view->hdr);
2294 }
2295
2296 /* read components states from the registry */
2297 ACTION_GetComponentInstallStates(package);
5a3c3b6a 2298 ACTION_GetFeatureInstallStates(package);
c5c55210
MM
2299
2300 TRACE("File calculations\n");
2301 msi_check_file_install_states( package );
2302
7d3e5973
AS
2303 TRACE("Evaluating Condition Table\n");
2304
a7a6f5f3 2305 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
84837d96
AS
2306 if (rc == ERROR_SUCCESS)
2307 {
443ad4d3
AS
2308 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2309 package);
ac6a413b 2310 msiobj_release(&view->hdr);
84837d96 2311 }
7d3e5973
AS
2312
2313 TRACE("Enabling or Disabling Components\n");
38d67a45 2314 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
7d3e5973 2315 {
9375fd9f 2316 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
7d3e5973 2317 {
9375fd9f
MM
2318 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2319 comp->Enabled = FALSE;
7d3e5973 2320 }
bf515184
JH
2321 else
2322 comp->Enabled = TRUE;
7d3e5973
AS
2323 }
2324
a7a6f5f3 2325 MSI_SetPropertyW(package,szCosting,szOne);
8cc14a93 2326 /* set default run level if not set */
062ad505 2327 level = msi_dup_property( package, szlevel );
8cc14a93
AS
2328 if (!level)
2329 MSI_SetPropertyW(package,szlevel, szOne);
ee034ba4 2330 msi_free(level);
ae1aa32c 2331
ece5a047
JH
2332 /* FIXME: check volume disk space */
2333 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2334
7c7f0bb2 2335 return MSI_SetFeatureStates(package);
401bd3f7
AS
2336}
2337
da8b3dd7 2338/* OK this value is "interpreted" and then formatted based on the
6e160f14 2339 first few characters */
09b0abaa 2340static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
401bd3f7
AS
2341 DWORD *size)
2342{
2343 LPSTR data = NULL;
2f658cb3 2344
6e160f14 2345 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
401bd3f7 2346 {
6e160f14
AS
2347 if (value[1]=='x')
2348 {
2349 LPWSTR ptr;
2350 CHAR byte[5];
6186b2be 2351 LPWSTR deformated = NULL;
6e160f14
AS
2352 int count;
2353
a7a6f5f3 2354 deformat_string(package, &value[2], &deformated);
6e160f14
AS
2355
2356 /* binary value type */
6186b2be
AS
2357 ptr = deformated;
2358 *type = REG_BINARY;
2359 if (strlenW(ptr)%2)
2360 *size = (strlenW(ptr)/2)+1;
2361 else
2362 *size = strlenW(ptr)/2;
2363
ee034ba4 2364 data = msi_alloc(*size);
6186b2be 2365
6e160f14
AS
2366 byte[0] = '0';
2367 byte[1] = 'x';
2368 byte[4] = 0;
2369 count = 0;
6186b2be
AS
2370 /* if uneven pad with a zero in front */
2371 if (strlenW(ptr)%2)
2372 {
2373 byte[2]= '0';
2374 byte[3]= *ptr;
2375 ptr++;
2376 data[count] = (BYTE)strtol(byte,NULL,0);
2377 count ++;
2378 TRACE("Uneven byte count\n");
2379 }
6e160f14
AS
2380 while (*ptr)
2381 {
2382 byte[2]= *ptr;
2383 ptr++;
2384 byte[3]= *ptr;
2385 ptr++;
2386 data[count] = (BYTE)strtol(byte,NULL,0);
2387 count ++;
2388 }
ee034ba4 2389 msi_free(deformated);
6e160f14 2390
f1d4646a 2391 TRACE("Data %i bytes(%i)\n",*size,count);
6e160f14
AS
2392 }
2393 else
2394 {
2395 LPWSTR deformated;
b6bc6aa6
AS
2396 LPWSTR p;
2397 DWORD d = 0;
a7a6f5f3 2398 deformat_string(package, &value[1], &deformated);
6e160f14
AS
2399
2400 *type=REG_DWORD;
2401 *size = sizeof(DWORD);
ee034ba4 2402 data = msi_alloc(*size);
b6bc6aa6
AS
2403 p = deformated;
2404 if (*p == '-')
2405 p++;
2406 while (*p)
2407 {
2408 if ( (*p < '0') || (*p > '9') )
2409 break;
2410 d *= 10;
2411 d += (*p - '0');
2412 p++;
2413 }
2414 if (deformated[0] == '-')
2415 d = -d;
2416 *(LPDWORD)data = d;
f1d4646a 2417 TRACE("DWORD %i\n",*(LPDWORD)data);
6e160f14 2418
ee034ba4 2419 msi_free(deformated);
6e160f14 2420 }
401bd3f7
AS
2421 }
2422 else
2423 {
54c67dd1 2424 static const WCHAR szMulti[] = {'[','~',']',0};
09b0abaa 2425 LPCWSTR ptr;
6e160f14
AS
2426 *type=REG_SZ;
2427
401bd3f7 2428 if (value[0]=='#')
6e160f14
AS
2429 {
2430 if (value[1]=='%')
2431 {
2432 ptr = &value[2];
2433 *type=REG_EXPAND_SZ;
2434 }
2435 else
2436 ptr = &value[1];
2437 }
2438 else
401bd3f7
AS
2439 ptr=value;
2440
54c67dd1
AS
2441 if (strstrW(value,szMulti))
2442 *type = REG_MULTI_SZ;
2443
2f658cb3
JH
2444 /* remove initial delimiter */
2445 if (!strncmpW(value, szMulti, 3))
2446 ptr = value + 3;
2447
a7a6f5f3 2448 *size = deformat_string(package, ptr,(LPWSTR*)&data);
2f658cb3
JH
2449
2450 /* add double NULL terminator */
2451 if (*type == REG_MULTI_SZ)
2452 {
21b4af1b
JH
2453 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2454 data = msi_realloc_zero(data, *size);
2f658cb3 2455 }
401bd3f7
AS
2456 }
2457 return data;
2458}
2459
92ef78ee 2460static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
401bd3f7 2461{
5f3ac30b 2462 MSIPACKAGE *package = param;
92ef78ee
AS
2463 static const WCHAR szHCR[] =
2464 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2465 'R','O','O','T','\\',0};
2466 static const WCHAR szHCU[] =
2467 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2468 'U','S','E','R','\\',0};
2469 static const WCHAR szHLM[] =
2470 {'H','K','E','Y','_','L','O','C','A','L','_',
2471 'M','A','C','H','I','N','E','\\',0};
2472 static const WCHAR szHU[] =
2473 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2474
2475 LPSTR value_data = NULL;
2476 HKEY root_key, hkey;
2477 DWORD type,size;
2478 LPWSTR deformated;
2479 LPCWSTR szRoot, component, name, key, value;
38d67a45 2480 MSICOMPONENT *comp;
92ef78ee
AS
2481 MSIRECORD * uirow;
2482 LPWSTR uikey;
2483 INT root;
2484 BOOL check_first = FALSE;
401bd3f7 2485 UINT rc;
401bd3f7 2486
92ef78ee 2487 ui_progress(package,2,0,0,0);
7d3e5973 2488
92ef78ee
AS
2489 value = NULL;
2490 key = NULL;
2491 uikey = NULL;
2492 name = NULL;
401bd3f7 2493
92ef78ee 2494 component = MSI_RecordGetString(row, 6);
38d67a45 2495 comp = get_loaded_component(package,component);
0946c42d
JD
2496 if (!comp)
2497 return ERROR_SUCCESS;
d2c395ad 2498
d693f461 2499 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
401bd3f7 2500 {
92ef78ee
AS
2501 TRACE("Skipping write due to disabled component %s\n",
2502 debugstr_w(component));
90c57396 2503
38d67a45 2504 comp->Action = comp->Installed;
90c57396 2505
92ef78ee
AS
2506 return ERROR_SUCCESS;
2507 }
7d3e5973 2508
38d67a45 2509 comp->Action = INSTALLSTATE_LOCAL;
90c57396 2510
92ef78ee
AS
2511 name = MSI_RecordGetString(row, 4);
2512 if( MSI_RecordIsNull(row,5) && name )
2513 {
2514 /* null values can have special meanings */
2515 if (name[0]=='-' && name[1] == 0)
2516 return ERROR_SUCCESS;
2517 else if ((name[0]=='+' && name[1] == 0) ||
2518 (name[0] == '*' && name[1] == 0))
b6bc6aa6 2519 name = NULL;
92ef78ee
AS
2520 check_first = TRUE;
2521 }
401bd3f7 2522
92ef78ee
AS
2523 root = MSI_RecordGetInteger(row,2);
2524 key = MSI_RecordGetString(row, 3);
2525
2526 /* get the root key */
2527 switch (root)
2528 {
0713f098
AS
2529 case -1:
2530 {
2531 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
062ad505 2532 LPWSTR all_users = msi_dup_property( package, szALLUSER );
0713f098
AS
2533 if (all_users && all_users[0] == '1')
2534 {
2535 root_key = HKEY_LOCAL_MACHINE;
2536 szRoot = szHLM;
2537 }
2538 else
2539 {
2540 root_key = HKEY_CURRENT_USER;
2541 szRoot = szHCU;
2542 }
ee034ba4 2543 msi_free(all_users);
0713f098
AS
2544 }
2545 break;
92ef78ee
AS
2546 case 0: root_key = HKEY_CLASSES_ROOT;
2547 szRoot = szHCR;
2548 break;
2549 case 1: root_key = HKEY_CURRENT_USER;
2550 szRoot = szHCU;
2551 break;
2552 case 2: root_key = HKEY_LOCAL_MACHINE;
2553 szRoot = szHLM;
2554 break;
2555 case 3: root_key = HKEY_USERS;
2556 szRoot = szHU;
2557 break;
2558 default:
401bd3f7
AS
2559 ERR("Unknown root %i\n",root);
2560 root_key=NULL;
9db0e072 2561 szRoot = NULL;
401bd3f7 2562 break;
92ef78ee
AS
2563 }
2564 if (!root_key)
2565 return ERROR_SUCCESS;
401bd3f7 2566
92ef78ee
AS
2567 deformat_string(package, key , &deformated);
2568 size = strlenW(deformated) + strlenW(szRoot) + 1;
ee034ba4 2569 uikey = msi_alloc(size*sizeof(WCHAR));
92ef78ee
AS
2570 strcpyW(uikey,szRoot);
2571 strcatW(uikey,deformated);
1416b101 2572
92ef78ee
AS
2573 if (RegCreateKeyW( root_key, deformated, &hkey))
2574 {
2575 ERR("Could not create key %s\n",debugstr_w(deformated));
ee034ba4
MM
2576 msi_free(deformated);
2577 msi_free(uikey);
92ef78ee
AS
2578 return ERROR_SUCCESS;
2579 }
ee034ba4 2580 msi_free(deformated);
6e160f14 2581
92ef78ee
AS
2582 value = MSI_RecordGetString(row,5);
2583 if (value)
2584 value_data = parse_value(package, value, &type, &size);
2585 else
2586 {
2587 static const WCHAR szEmpty[] = {0};
2588 value_data = (LPSTR)strdupW(szEmpty);
06bf8ea2 2589 size = sizeof(szEmpty);
92ef78ee
AS
2590 type = REG_SZ;
2591 }
401bd3f7 2592
92ef78ee 2593 deformat_string(package, name, &deformated);
1416b101 2594
92ef78ee
AS
2595 if (!check_first)
2596 {
2597 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2598 debugstr_w(uikey));
16466af7 2599 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
92ef78ee
AS
2600 }
2601 else
2602 {
2603 DWORD sz = 0;
2604 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2605 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
98e38082 2606 {
92ef78ee
AS
2607 TRACE("value %s of %s checked already exists\n",
2608 debugstr_w(deformated), debugstr_w(uikey));
98e38082
AS
2609 }
2610 else
2611 {
92ef78ee
AS
2612 TRACE("Checked and setting value %s of %s\n",
2613 debugstr_w(deformated), debugstr_w(uikey));
2614 if (deformated || size)
16466af7 2615 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
98e38082 2616 }
92ef78ee
AS
2617 }
2618 RegCloseKey(hkey);
d2c395ad 2619
92ef78ee
AS
2620 uirow = MSI_CreateRecord(3);
2621 MSI_RecordSetStringW(uirow,2,deformated);
2622 MSI_RecordSetStringW(uirow,1,uikey);
d2c395ad 2623
92ef78ee
AS
2624 if (type == REG_SZ)
2625 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2626 else
2627 MSI_RecordSetStringW(uirow,3,value);
d2c395ad 2628
92ef78ee
AS
2629 ui_actiondata(package,szWriteRegistryValues,uirow);
2630 msiobj_release( &uirow->hdr );
d2c395ad 2631
ee034ba4
MM
2632 msi_free(value_data);
2633 msi_free(deformated);
2634 msi_free(uikey);
92ef78ee
AS
2635
2636 return ERROR_SUCCESS;
2637}
2638
2639static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2640{
2641 UINT rc;
2642 MSIQUERY * view;
2643 static const WCHAR ExecSeqQuery[] =
2644 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2645 '`','R','e','g','i','s','t','r','y','`',0 };
2646
92ef78ee
AS
2647 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2648 if (rc != ERROR_SUCCESS)
2649 return ERROR_SUCCESS;
2650
2651 /* increment progress bar each time action data is sent */
2652 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2653
2654 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
401bd3f7 2655
a7a6f5f3 2656 msiobj_release(&view->hdr);
401bd3f7
AS
2657 return rc;
2658}
2659
a7a6f5f3 2660static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
7d3e5973 2661{
9cd707da
AS
2662 package->script->CurrentlyScripting = TRUE;
2663
7d3e5973
AS
2664 return ERROR_SUCCESS;
2665}
2666
ae1aa32c 2667
a7a6f5f3 2668static UINT ACTION_InstallValidate(MSIPACKAGE *package)
7d3e5973 2669{
38d67a45 2670 MSICOMPONENT *comp;
7d3e5973 2671 DWORD progress = 0;
bd1bbc17 2672 DWORD total = 0;
8e233e9b
AS
2673 static const WCHAR q1[]=
2674 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
98e38082 2675 '`','R','e','g','i','s','t','r','y','`',0};
7d3e5973 2676 UINT rc;
a7a6f5f3 2677 MSIQUERY * view;
1da2858c 2678 MSIFEATURE *feature;
e18f8abe 2679 MSIFILE *file;
7d3e5973 2680
f3f12ab5 2681 TRACE("InstallValidate\n");
7d3e5973 2682
a7a6f5f3 2683 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
f3f12ab5 2684 if (rc == ERROR_SUCCESS)
a7a6f5f3 2685 {
f3f12ab5
MM
2686 MSI_IterateRecords( view, &progress, NULL, package );
2687 msiobj_release( &view->hdr );
2688 total += progress * REG_PROGRESS_VALUE;
a7a6f5f3 2689 }
7d3e5973 2690
38d67a45 2691 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
38d67a45 2692 total += COMPONENT_PROGRESS_VALUE;
f3f12ab5 2693
e18f8abe 2694 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
e18f8abe 2695 total += file->FileSize;
f3f12ab5 2696
bd1bbc17 2697 ui_progress(package,0,total,0,0);
7d3e5973 2698
1da2858c 2699 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
b39d8fc2 2700 {
b39d8fc2
AS
2701 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2702 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2703 feature->ActionRequest);
2704 }
2705
7d3e5973
AS
2706 return ERROR_SUCCESS;
2707}
2708
c79f4e21
AS
2709static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2710{
5f3ac30b 2711 MSIPACKAGE* package = param;
c79f4e21
AS
2712 LPCWSTR cond = NULL;
2713 LPCWSTR message = NULL;
bafc4dc3
JH
2714 UINT r;
2715
c79f4e21
AS
2716 static const WCHAR title[]=
2717 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2718
2719 cond = MSI_RecordGetString(row,1);
2720
bafc4dc3
JH
2721 r = MSI_EvaluateConditionW(package,cond);
2722 if (r == MSICONDITION_FALSE)
c79f4e21 2723 {
bafc4dc3
JH
2724 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2725 {
2726 LPWSTR deformated;
2727 message = MSI_RecordGetString(row,2);
2728 deformat_string(package,message,&deformated);
2729 MessageBoxW(NULL,deformated,title,MB_OK);
2730 msi_free(deformated);
2731 }
2732
2733 return ERROR_INSTALL_FAILURE;
c79f4e21
AS
2734 }
2735
2736 return ERROR_SUCCESS;
2737}
2738
a7a6f5f3 2739static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
5b936ca2
AS
2740{
2741 UINT rc;
f3c8b830 2742 MSIQUERY * view = NULL;
8e233e9b
AS
2743 static const WCHAR ExecSeqQuery[] =
2744 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082 2745 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
5b936ca2
AS
2746
2747 TRACE("Checking launch conditions\n");
2748
a7a6f5f3 2749 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5b936ca2 2750 if (rc != ERROR_SUCCESS)
84837d96 2751 return ERROR_SUCCESS;
5b936ca2 2752
c79f4e21 2753 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
a7a6f5f3 2754 msiobj_release(&view->hdr);
c79f4e21 2755
5b936ca2
AS
2756 return rc;
2757}
7d3e5973 2758
38d67a45 2759static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
b942e186 2760{
b942e186 2761
efcc1ec5 2762 if (!cmp->KeyPath)
8cedb218 2763 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
efcc1ec5 2764
b6bc6aa6 2765 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
b942e186 2766 {
6269f00c 2767 MSIRECORD * row = 0;
0b352c7f 2768 UINT root,len;
09b0abaa
AS
2769 LPWSTR deformated,buffer,deformated_name;
2770 LPCWSTR key,name;
8e233e9b
AS
2771 static const WCHAR ExecSeqQuery[] =
2772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082
AS
2773 '`','R','e','g','i','s','t','r','y','`',' ',
2774 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2775 ' ','=',' ' ,'\'','%','s','\'',0 };
b6bc6aa6 2776 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
8e233e9b
AS
2777 static const WCHAR fmt2[]=
2778 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
6269f00c 2779
0b352c7f
MM
2780 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2781 if (!row)
6269f00c 2782 return NULL;
6269f00c
AS
2783
2784 root = MSI_RecordGetInteger(row,2);
09b0abaa
AS
2785 key = MSI_RecordGetString(row, 3);
2786 name = MSI_RecordGetString(row, 4);
6269f00c
AS
2787 deformat_string(package, key , &deformated);
2788 deformat_string(package, name, &deformated_name);
2789
e15e5179 2790 len = strlenW(deformated) + 6;
6269f00c
AS
2791 if (deformated_name)
2792 len+=strlenW(deformated_name);
2793
ee034ba4 2794 buffer = msi_alloc( len *sizeof(WCHAR));
6269f00c
AS
2795
2796 if (deformated_name)
2797 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2798 else
2799 sprintfW(buffer,fmt,root,deformated);
2800
ee034ba4
MM
2801 msi_free(deformated);
2802 msi_free(deformated_name);
6269f00c 2803 msiobj_release(&row->hdr);
6269f00c
AS
2804
2805 return buffer;
2806 }
b6bc6aa6 2807 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
6269f00c
AS
2808 {
2809 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
fa384f6b 2810 return NULL;
b942e186
AS
2811 }
2812 else
2813 {
e18f8abe 2814 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
fcb20c53 2815
e18f8abe
MM
2816 if (file)
2817 return strdupW( file->TargetPath );
b942e186 2818 }
fa384f6b 2819 return NULL;
b942e186
AS
2820}
2821
ac6f562b 2822static HKEY openSharedDLLsKey(void)
b6bc6aa6
AS
2823{
2824 HKEY hkey=0;
8e233e9b
AS
2825 static const WCHAR path[] =
2826 {'S','o','f','t','w','a','r','e','\\',
2827 'M','i','c','r','o','s','o','f','t','\\',
2828 'W','i','n','d','o','w','s','\\',
2829 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2830 'S','h','a','r','e','d','D','L','L','s',0};
b6bc6aa6
AS
2831
2832 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2833 return hkey;
2834}
2835
2836static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2837{
2838 HKEY hkey;
2839 DWORD count=0;
2840 DWORD type;
2841 DWORD sz = sizeof(count);
2842 DWORD rc;
2843
2844 hkey = openSharedDLLsKey();
2845 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2846 if (rc != ERROR_SUCCESS)
2847 count = 0;
2848 RegCloseKey(hkey);
2849 return count;
2850}
2851
2852static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2853{
2854 HKEY hkey;
2855
2856 hkey = openSharedDLLsKey();
2857 if (count > 0)
4db02cdb 2858 msi_reg_set_val_dword( hkey, path, count );
b6bc6aa6
AS
2859 else
2860 RegDeleteValueW(hkey,path);
2861 RegCloseKey(hkey);
2862 return count;
2863}
2864
2865/*
2866 * Return TRUE if the count should be written out and FALSE if not
2867 */
38d67a45 2868static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
b6bc6aa6 2869{
1da2858c 2870 MSIFEATURE *feature;
b6bc6aa6
AS
2871 INT count = 0;
2872 BOOL write = FALSE;
b6bc6aa6
AS
2873
2874 /* only refcount DLLs */
efcc1ec5 2875 if (comp->KeyPath == NULL ||
38d67a45
MM
2876 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2877 comp->Attributes & msidbComponentAttributesODBCDataSource)
b6bc6aa6
AS
2878 write = FALSE;
2879 else
2880 {
38d67a45 2881 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
b6bc6aa6
AS
2882 write = (count > 0);
2883
38d67a45 2884 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
b6bc6aa6
AS
2885 write = TRUE;
2886 }
2887
2888 /* increment counts */
1da2858c 2889 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
b6bc6aa6 2890 {
3f2d5d7f 2891 ComponentList *cl;
b6bc6aa6 2892
1da2858c 2893 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
b6bc6aa6
AS
2894 continue;
2895
1da2858c 2896 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
b6bc6aa6 2897 {
38d67a45 2898 if ( cl->component == comp )
b6bc6aa6
AS
2899 count++;
2900 }
2901 }
e18f8abe 2902
b6bc6aa6 2903 /* decrement counts */
1da2858c 2904 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
b6bc6aa6 2905 {
3f2d5d7f
MM
2906 ComponentList *cl;
2907
1da2858c 2908 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
b6bc6aa6
AS
2909 continue;
2910
1da2858c 2911 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
b6bc6aa6 2912 {
38d67a45 2913 if ( cl->component == comp )
b6bc6aa6
AS
2914 count--;
2915 }
2916 }
2917
2918 /* ref count all the files in the component */
2919 if (write)
e18f8abe
MM
2920 {
2921 MSIFILE *file;
2922
2923 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
b6bc6aa6 2924 {
e18f8abe
MM
2925 if (file->Component == comp)
2926 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
b6bc6aa6 2927 }
e18f8abe 2928 }
b6bc6aa6 2929
5644f05e 2930 /* add a count for permanent */
38d67a45 2931 if (comp->Attributes & msidbComponentAttributesPermanent)
b6bc6aa6
AS
2932 count ++;
2933
38d67a45 2934 comp->RefCount = count;
b6bc6aa6
AS
2935
2936 if (write)
38d67a45 2937 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
b6bc6aa6
AS
2938}
2939
a7a6f5f3 2940static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
b942e186 2941{
68b07494
AS
2942 WCHAR squished_pc[GUID_SIZE];
2943 WCHAR squished_cc[GUID_SIZE];
b942e186 2944 UINT rc;
38d67a45 2945 MSICOMPONENT *comp;
4aa3a997 2946 HKEY hkey;
b942e186 2947
fc6b9dd4
JH
2948 TRACE("\n");
2949
adaef111 2950 squash_guid(package->ProductCode,squished_pc);
bd1bbc17 2951 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
38d67a45
MM
2952
2953 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
b942e186 2954 {
fe8cd388
MM
2955 MSIRECORD * uirow;
2956
bd1bbc17 2957 ui_progress(package,2,0,0,0);
fe8cd388
MM
2958 if (!comp->ComponentId)
2959 continue;
b942e186 2960
fe8cd388 2961 squash_guid(comp->ComponentId,squished_cc);
a3a2eaea 2962
fe8cd388
MM
2963 msi_free(comp->FullKeypath);
2964 comp->FullKeypath = resolve_keypath( package, comp );
b6bc6aa6 2965
fe8cd388 2966 ACTION_RefCountComponent( package, comp );
b6bc6aa6 2967
fe8cd388 2968 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
38d67a45 2969 debugstr_w(comp->Component),
c5a1443f 2970 debugstr_w(squished_cc),
fe8cd388 2971 debugstr_w(comp->FullKeypath),
38d67a45 2972 comp->RefCount);
96dd6ce1
JH
2973
2974 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2975 ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
fe8cd388 2976 {
fe8cd388
MM
2977 if (!comp->FullKeypath)
2978 continue;
b6bc6aa6 2979
288af81a 2980 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
b198f4f2
JH
2981 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2982 &hkey, TRUE);
288af81a 2983 else
b198f4f2
JH
2984 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2985 &hkey, TRUE);
288af81a 2986
4aa3a997
JH
2987 if (rc != ERROR_SUCCESS)
2988 continue;
b6bc6aa6 2989
fe8cd388 2990 if (comp->Attributes & msidbComponentAttributesPermanent)
fa384f6b 2991 {
fe8cd388
MM
2992 static const WCHAR szPermKey[] =
2993 { '0','0','0','0','0','0','0','0','0','0','0','0',
2994 '0','0','0','0','0','0','0','0','0','0','0','0',
2995 '0','0','0','0','0','0','0','0',0 };
b39d8fc2 2996
4aa3a997 2997 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
fe8cd388 2998 }
b39d8fc2 2999
96dd6ce1
JH
3000 if (comp->Action == INSTALLSTATE_LOCAL)
3001 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3002 else
3003 {
3004 MSIFILE *file;
3005 MSIRECORD *row;
3006 LPWSTR ptr, ptr2;
3007 WCHAR source[MAX_PATH];
3008 WCHAR base[MAX_PATH];
d15fddf6 3009 LPWSTR sourcepath;
96dd6ce1
JH
3010
3011 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3012 static const WCHAR query[] = {
3013 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3014 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3015 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3016 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3017 '`','D','i','s','k','I','d','`',0};
3018
3019 file = get_loaded_file(package, comp->KeyPath);
3020 if (!file)
3021 continue;
3022
3023 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3024 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3025 ptr2 = strrchrW(source, '\\') + 1;
3026 msiobj_release(&row->hdr);
3027
3028 lstrcpyW(base, package->PackagePath);
3029 ptr = strrchrW(base, '\\');
3030 *(ptr + 1) = '\0';
3031
d15fddf6
JH
3032 sourcepath = resolve_file_source(package, file);
3033 ptr = sourcepath + lstrlenW(base);
96dd6ce1 3034 lstrcpyW(ptr2, ptr);
d15fddf6 3035 msi_free(sourcepath);
96dd6ce1
JH
3036
3037 msi_reg_set_val_str(hkey, squished_pc, source);
3038 }
4aa3a997 3039 RegCloseKey(hkey);
fe8cd388 3040 }
4aa3a997 3041 else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
288af81a
JH
3042 {
3043 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
a9e02909 3044 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
288af81a 3045 else
a9e02909 3046 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
288af81a 3047 }
a3a2eaea
MM
3048
3049 /* UI stuff */
3050 uirow = MSI_CreateRecord(3);
3051 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3052 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3053 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3054 ui_actiondata(package,szProcessComponents,uirow);
3055 msiobj_release( &uirow->hdr );
3056 }
4aa3a997
JH
3057
3058 return ERROR_SUCCESS;
b942e186
AS
3059}
3060
6e821739
AS
3061typedef struct {
3062 CLSID clsid;
3063 LPWSTR source;
3064
3065 LPWSTR path;
3066 ITypeLib *ptLib;
3067} typelib_struct;
3068
f9acfe63 3069static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
6e821739
AS
3070 LPWSTR lpszName, LONG_PTR lParam)
3071{
3072 TLIBATTR *attr;
3073 typelib_struct *tl_struct = (typelib_struct*) lParam;
3074 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3075 int sz;
3076 HRESULT res;
3077
3078 if (!IS_INTRESOURCE(lpszName))
3079 {
3080 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3081 return TRUE;
3082 }
3083
3084 sz = strlenW(tl_struct->source)+4;
3085 sz *= sizeof(WCHAR);
3086
2acf800f 3087 if ((INT_PTR)lpszName == 1)
ca8c4e41
AS
3088 tl_struct->path = strdupW(tl_struct->source);
3089 else
3090 {
ee034ba4 3091 tl_struct->path = msi_alloc(sz);
ca8c4e41
AS
3092 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3093 }
6e821739
AS
3094
3095 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3096 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
704ebf28 3097 if (FAILED(res))
6e821739 3098 {
ee034ba4 3099 msi_free(tl_struct->path);
6e821739
AS
3100 tl_struct->path = NULL;
3101
3102 return TRUE;
3103 }
3104
3105 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3106 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3107 {
3108 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3109 return FALSE;
3110 }
3111
ee034ba4 3112 msi_free(tl_struct->path);
6e821739
AS
3113 tl_struct->path = NULL;
3114
3115 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3116 ITypeLib_Release(tl_struct->ptLib);
3117
3118 return TRUE;
3119}
3120
234dc4b2 3121static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
fcb20c53 3122{
5f3ac30b 3123 MSIPACKAGE* package = param;
234dc4b2 3124 LPCWSTR component;
38d67a45 3125 MSICOMPONENT *comp;
e18f8abe 3126 MSIFILE *file;
234dc4b2 3127 typelib_struct tl_struct;
469e4a5c 3128 ITypeLib *tlib;
234dc4b2 3129 HMODULE module;
469e4a5c
JH
3130 HRESULT hr;
3131
234dc4b2
AS
3132 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3133
3134 component = MSI_RecordGetString(row,3);
38d67a45
MM
3135 comp = get_loaded_component(package,component);
3136 if (!comp)
84837d96 3137 return ERROR_SUCCESS;
fcb20c53 3138
d693f461 3139 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
fcb20c53 3140 {
234dc4b2 3141 TRACE("Skipping typelib reg due to disabled component\n");
fcb20c53 3142
38d67a45 3143 comp->Action = comp->Installed;
fcb20c53 3144
234dc4b2
AS
3145 return ERROR_SUCCESS;
3146 }
fcb20c53 3147
38d67a45 3148 comp->Action = INSTALLSTATE_LOCAL;
fcb20c53 3149
e18f8abe
MM
3150 file = get_loaded_file( package, comp->KeyPath );
3151 if (!file)
234dc4b2 3152 return ERROR_SUCCESS;
90c57396 3153
e18f8abe 3154 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
51c6618d 3155 if (module)
234dc4b2 3156 {
51c6618d
MM
3157 LPCWSTR guid;
3158 guid = MSI_RecordGetString(row,1);
3159 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
e18f8abe 3160 tl_struct.source = strdupW( file->TargetPath );
234dc4b2 3161 tl_struct.path = NULL;
fcb20c53 3162
234dc4b2
AS
3163 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3164 (LONG_PTR)&tl_struct);
90c57396 3165
51c6618d 3166 if (tl_struct.path)
fcb20c53 3167 {
234dc4b2
AS
3168 LPWSTR help = NULL;
3169 LPCWSTR helpid;
3170 HRESULT res;
fcb20c53 3171
234dc4b2 3172 helpid = MSI_RecordGetString(row,6);
fcb20c53 3173
234dc4b2 3174 if (helpid)
8cedb218 3175 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
234dc4b2 3176 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
ee034ba4 3177 msi_free(help);
ba8200bf 3178
704ebf28 3179 if (FAILED(res))
234dc4b2
AS
3180 ERR("Failed to register type library %s\n",
3181 debugstr_w(tl_struct.path));
3182 else
fcb20c53 3183 {
234dc4b2 3184 ui_actiondata(package,szRegisterTypeLibraries,row);
6e821739 3185
234dc4b2 3186 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
6e821739 3187 }
234dc4b2
AS
3188
3189 ITypeLib_Release(tl_struct.ptLib);
ee034ba4 3190 msi_free(tl_struct.path);
fcb20c53
AS
3191 }
3192 else
234dc4b2
AS
3193 ERR("Failed to load type library %s\n",
3194 debugstr_w(tl_struct.source));
3195
3196 FreeLibrary(module);
ee034ba4 3197 msi_free(tl_struct.source);
fcb20c53 3198 }
234dc4b2 3199 else
469e4a5c
JH
3200 {
3201 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3202 if (FAILED(hr))
3203 {
3204 ERR("Failed to load type library: %08x\n", hr);
3205 return ERROR_FUNCTION_FAILED;
3206 }
3207
3208 ITypeLib_Release(tlib);
3209 }
234dc4b2
AS
3210
3211 return ERROR_SUCCESS;
3212}
3213
3214static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3215{
3216 /*
3217 * OK this is a bit confusing.. I am given a _Component key and I believe
3218 * that the file that is being registered as a type library is the "key file
3219 * of that component" which I interpret to mean "The file in the KeyPath of
3220 * that component".
3221 */
3222 UINT rc;
3223 MSIQUERY * view;
3224 static const WCHAR Query[] =
3225 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3226 '`','T','y','p','e','L','i','b','`',0};
3227
234dc4b2
AS
3228 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3229 if (rc != ERROR_SUCCESS)
3230 return ERROR_SUCCESS;
3231
3232 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
a7a6f5f3 3233 msiobj_release(&view->hdr);
fcb20c53 3234 return rc;
fcb20c53
AS
3235}
3236
9adacf6a 3237static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2cf222f9 3238{
5f3ac30b 3239 MSIPACKAGE *package = param;
477bce38 3240 LPWSTR target_file, target_folder, filename;
4ac85674 3241 LPCWSTR buffer, extension;
38d67a45 3242 MSICOMPONENT *comp;
9adacf6a 3243 static const WCHAR szlnk[]={'.','l','n','k',0};
20c57466
MM
3244 IShellLinkW *sl = NULL;
3245 IPersistFile *pf = NULL;
2cf222f9
AS
3246 HRESULT res;
3247
9adacf6a 3248 buffer = MSI_RecordGetString(row,4);
38d67a45
MM
3249 comp = get_loaded_component(package,buffer);
3250 if (!comp)
84837d96 3251 return ERROR_SUCCESS;
2cf222f9 3252
d693f461 3253 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2cf222f9 3254 {
9adacf6a 3255 TRACE("Skipping shortcut creation due to disabled component\n");
2cf222f9 3256
38d67a45 3257 comp->Action = comp->Installed;
2cf222f9 3258
9adacf6a
AS
3259 return ERROR_SUCCESS;
3260 }
2cf222f9 3261
38d67a45 3262 comp->Action = INSTALLSTATE_LOCAL;
2cf222f9 3263
9adacf6a 3264 ui_actiondata(package,szCreateShortcuts,row);
90c57396 3265
9adacf6a
AS
3266 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3267 &IID_IShellLinkW, (LPVOID *) &sl );
90c57396 3268
20c57466 3269 if (FAILED( res ))
9adacf6a 3270 {
20c57466
MM
3271 ERR("CLSID_ShellLink not available\n");
3272 goto err;
9adacf6a 3273 }
2cf222f9 3274
9adacf6a 3275 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
20c57466 3276 if (FAILED( res ))
9adacf6a 3277 {
20c57466
MM
3278 ERR("QueryInterface(IID_IPersistFile) failed\n");
3279 goto err;
9adacf6a 3280 }
90c57396 3281
9adacf6a 3282 buffer = MSI_RecordGetString(row,2);
8cedb218 3283 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2cf222f9 3284
5644f05e 3285 /* may be needed because of a bug somewhere else */
9adacf6a 3286 create_full_pathW(target_folder);
2cf222f9 3287
477bce38 3288 filename = msi_dup_record_field( row, 3 );
9adacf6a 3289 reduce_to_longfilename(filename);
4ac85674
RS
3290
3291 extension = strchrW(filename,'.');
3292 if (!extension || strcmpiW(extension,szlnk))
3293 {
3294 int len = strlenW(filename);
3295 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3296 memcpy(filename + len, szlnk, sizeof(szlnk));
3297 }
9adacf6a 3298 target_file = build_directory_name(2, target_folder, filename);
ee034ba4 3299 msi_free(target_folder);
477bce38 3300 msi_free(filename);
2cf222f9 3301
9adacf6a
AS
3302 buffer = MSI_RecordGetString(row,5);
3303 if (strchrW(buffer,'['))
3304 {
3305 LPWSTR deformated;
3306 deformat_string(package,buffer,&deformated);
3307 IShellLinkW_SetPath(sl,deformated);
ee034ba4 3308 msi_free(deformated);
9adacf6a
AS
3309 }
3310 else
3311 {
9adacf6a 3312 FIXME("poorly handled shortcut format, advertised shortcut\n");
566c69e7 3313 IShellLinkW_SetPath(sl,comp->FullKeypath);
9adacf6a 3314 }
2cf222f9 3315
9adacf6a
AS
3316 if (!MSI_RecordIsNull(row,6))
3317 {
3318 LPWSTR deformated;
3319 buffer = MSI_RecordGetString(row,6);
3320 deformat_string(package,buffer,&deformated);
3321 IShellLinkW_SetArguments(sl,deformated);
ee034ba4 3322 msi_free(deformated);
9adacf6a 3323 }
2cf222f9 3324
9adacf6a
AS
3325 if (!MSI_RecordIsNull(row,7))
3326 {
3327 buffer = MSI_RecordGetString(row,7);
3328 IShellLinkW_SetDescription(sl,buffer);
3329 }
8cc14a93 3330
9adacf6a
AS
3331 if (!MSI_RecordIsNull(row,8))
3332 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
2cf222f9 3333
9adacf6a
AS
3334 if (!MSI_RecordIsNull(row,9))
3335 {
75658d7a 3336 LPWSTR Path;
9adacf6a 3337 INT index;
2cf222f9 3338
9adacf6a 3339 buffer = MSI_RecordGetString(row,9);
2cf222f9 3340
75658d7a 3341 Path = build_icon_path(package,buffer);
9adacf6a 3342 index = MSI_RecordGetInteger(row,10);
2cf222f9 3343
ab378803
RS
3344 /* no value means 0 */
3345 if (index == MSI_NULL_INTEGER)
3346 index = 0;
3347
9adacf6a 3348 IShellLinkW_SetIconLocation(sl,Path,index);
ee034ba4 3349 msi_free(Path);
9adacf6a 3350 }
2cf222f9 3351
9adacf6a
AS
3352 if (!MSI_RecordIsNull(row,11))
3353 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
2cf222f9 3354
9adacf6a
AS
3355 if (!MSI_RecordIsNull(row,12))
3356 {
3357 LPWSTR Path;
3358 buffer = MSI_RecordGetString(row,12);
8cedb218 3359 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
43f7f3ec
MM
3360 if (Path)
3361 IShellLinkW_SetWorkingDirectory(sl,Path);
ee034ba4 3362 msi_free(Path);
9adacf6a 3363 }
2cf222f9 3364
9adacf6a
AS
3365 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3366 IPersistFile_Save(pf,target_file,FALSE);
2cf222f9 3367
ee034ba4 3368 msi_free(target_file);
2cf222f9 3369
20c57466
MM
3370err:
3371 if (pf)
3372 IPersistFile_Release( pf );
3373 if (sl)
3374 IShellLinkW_Release( sl );
2cf222f9 3375
9adacf6a
AS
3376 return ERROR_SUCCESS;
3377}
2cf222f9 3378
9adacf6a
AS
3379static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3380{
3381 UINT rc;
3382 HRESULT res;
3383 MSIQUERY * view;
3384 static const WCHAR Query[] =
3385 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3386 '`','S','h','o','r','t','c','u','t','`',0};
fa384f6b 3387
9adacf6a
AS
3388 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3389 if (rc != ERROR_SUCCESS)
3390 return ERROR_SUCCESS;
3391
3392 res = CoInitialize( NULL );
2cf222f9 3393
9adacf6a
AS
3394 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3395 msiobj_release(&view->hdr);
2cf222f9 3396
dd1ca6ca
HL
3397 if (SUCCEEDED(res))
3398 CoUninitialize();
2cf222f9 3399
8f0a7619
AS
3400 return rc;
3401}
3402
fac97bb8 3403static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
916ef949 3404{
5f3ac30b 3405 MSIPACKAGE* package = param;
916ef949 3406 HANDLE the_file;
75658d7a
MM
3407 LPWSTR FilePath;
3408 LPCWSTR FileName;
916ef949
AS
3409 CHAR buffer[1024];
3410 DWORD sz;
3411 UINT rc;
d2e48e01 3412 MSIRECORD *uirow;
916ef949
AS
3413
3414 FileName = MSI_RecordGetString(row,1);
3415 if (!FileName)
3416 {
3417 ERR("Unable to get FileName\n");
3418 return ERROR_SUCCESS;
3419 }
3420
75658d7a 3421 FilePath = build_icon_path(package,FileName);
916ef949
AS
3422
3423 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3424
3425 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3426 FILE_ATTRIBUTE_NORMAL, NULL);
3427
3428 if (the_file == INVALID_HANDLE_VALUE)
3429 {
3430 ERR("Unable to create file %s\n",debugstr_w(FilePath));
ee034ba4 3431 msi_free(FilePath);
916ef949
AS
3432 return ERROR_SUCCESS;
3433 }
3434
3435 do
3436 {
3437 DWORD write;
3438 sz = 1024;
3439 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3440 if (rc != ERROR_SUCCESS)
3441 {
3442 ERR("Failed to get stream\n");
3443 CloseHandle(the_file);
3444 DeleteFileW(FilePath);
3445 break;
3446 }
3447 WriteFile(the_file,buffer,sz,&write,NULL);
3448 } while (sz == 1024);
3449
ee034ba4 3450 msi_free(FilePath);
916ef949
AS
3451
3452 CloseHandle(the_file);
d2e48e01
RS
3453
3454 uirow = MSI_CreateRecord(1);
3455 MSI_RecordSetStringW(uirow,1,FileName);
3456 ui_actiondata(package,szPublishProduct,uirow);
3457 msiobj_release( &uirow->hdr );
3458
916ef949
AS
3459 return ERROR_SUCCESS;
3460}
2cf222f9 3461
fac97bb8
JH
3462static UINT msi_publish_icons(MSIPACKAGE *package)
3463{
3464 UINT r;
3465 MSIQUERY *view;
3466
3467 static const WCHAR query[]= {
3468 'S','E','L','E','C','T',' ','*',' ',
3469 'F','R','O','M',' ','`','I','c','o','n','`',0};
3470
3471 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3472 if (r == ERROR_SUCCESS)
3473 {
3474 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3475 msiobj_release(&view->hdr);
3476 }
3477
3478 return ERROR_SUCCESS;
3479}
3480
2d4e4b6a 3481static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
68e6071d
JH
3482{
3483 UINT r;
2d4e4b6a 3484 HKEY source;
68e6071d
JH
3485 LPWSTR buffer;
3486 MSIMEDIADISK *disk;
3487 MSISOURCELISTINFO *info;
3488
3489 static const WCHAR szEmpty[] = {0};
2d4e4b6a
JH
3490 static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
3491
3492 r = RegCreateKeyW(hkey, szSourceList, &source);
3493 if (r != ERROR_SUCCESS)
3494 return r;
3495
3496 RegCloseKey(source);
68e6071d
JH
3497
3498 buffer = strrchrW(package->PackagePath, '\\') + 1;
3499 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3500 package->Context, MSICODE_PRODUCT,
3501 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3502 if (r != ERROR_SUCCESS)
3503 return r;
3504
3505 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3506 package->Context, MSICODE_PRODUCT,
3507 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3508 if (r != ERROR_SUCCESS)
3509 return r;
3510
3511 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3512 package->Context, MSICODE_PRODUCT,
3513 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3514 if (r != ERROR_SUCCESS)
3515 return r;
3516
3517 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3518 {
3519 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3520 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3521 info->options, info->value);
3522 else
3523 MsiSourceListSetInfoW(package->ProductCode, NULL,
3524 info->context, info->options,
3525 info->property, info->value);
3526 }
3527
3528 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3529 {
3530 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3531 disk->context, disk->options,
3532 disk->disk_id, disk->volume_label, disk->disk_prompt);
3533 }
3534
3535 return ERROR_SUCCESS;
3536}
3537
ebeb5379
JH
3538static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3539{
3540 MSIHANDLE hdb, suminfo;
3541 WCHAR guids[MAX_PATH];
db2e8d2f 3542 WCHAR packcode[SQUISH_GUID_SIZE];
ebeb5379
JH
3543 LPWSTR buffer;
3544 LPWSTR ptr;
3545 DWORD langid;
3546 DWORD size;
3547 UINT r;
3548
3549 static const WCHAR szProductLanguage[] =
3550 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3551 static const WCHAR szARPProductIcon[] =
3552 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3553 static const WCHAR szProductVersion[] =
3554 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
ef640a6c
JH
3555 static const WCHAR szAssignment[] =
3556 {'A','s','s','i','g','n','m','e','n','t',0};
3557 static const WCHAR szAdvertiseFlags[] =
3558 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3559 static const WCHAR szClients[] =
3560 {'C','l','i','e','n','t','s',0};
3561 static const WCHAR szColon[] = {':',0};
ebeb5379
JH
3562
3563 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3564 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3565 msi_free(buffer);
3566
3567 langid = msi_get_property_int(package, szProductLanguage, 0);
3568 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3569
ebeb5379
JH
3570 /* FIXME */
3571 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3572
3573 buffer = msi_dup_property(package, szARPProductIcon);
3574 if (buffer)
3575 {
3576 LPWSTR path = build_icon_path(package,buffer);
3577 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3578 msi_free(path);
3579 msi_free(buffer);
3580 }
3581
3582 buffer = msi_dup_property(package, szProductVersion);
3583 if (buffer)
3584 {
3585 DWORD verdword = msi_version_str_to_dword(buffer);
3586 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3587 msi_free(buffer);
3588 }
3589
ef640a6c
JH
3590 msi_reg_set_val_dword(hkey, szAssignment, 0);
3591 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3592 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3593 msi_reg_set_val_str(hkey, szClients, szColon);
3594
ebeb5379
JH
3595 hdb = alloc_msihandle(&package->db->hdr);
3596 if (!hdb)
3597 return ERROR_NOT_ENOUGH_MEMORY;
3598
3599 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3600 MsiCloseHandle(hdb);
3601 if (r != ERROR_SUCCESS)
3602 goto done;
3603
3604 size = MAX_PATH;
3605 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3606 NULL, guids, &size);
3607 if (r != ERROR_SUCCESS)
3608 goto done;
3609
3610 ptr = strchrW(guids, ';');
3611 if (ptr) *ptr = 0;
db2e8d2f
JH
3612 squash_guid(guids, packcode);
3613 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
ebeb5379
JH
3614
3615done:
3616 MsiCloseHandle(suminfo);
3617 return ERROR_SUCCESS;
3618}
3619
cdb33f8a
JH
3620static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3621{
3622 UINT r;
3623 HKEY hkey;
3624 LPWSTR upgrade;
3625 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3626
3627 static const WCHAR szUpgradeCode[] =
3628 {'U','p','g','r','a','d','e','C','o','d','e',0};
3629
3630 upgrade = msi_dup_property(package, szUpgradeCode);
3631 if (!upgrade)
3632 return ERROR_SUCCESS;
3633
58e15439
JH
3634 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3635 {
3636 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3637 if (r != ERROR_SUCCESS)
3638 goto done;
3639 }
3640 else
3641 {
3642 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3643 if (r != ERROR_SUCCESS)
3644 goto done;
3645 }
cdb33f8a
JH
3646
3647 squash_guid(package->ProductCode, squashed_pc);
3648 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3649
3650 RegCloseKey(hkey);
3651
3652done:
3653 msi_free(upgrade);
3654 return r;
3655}
3656
a2df31ae
JH
3657static BOOL msi_check_publish(MSIPACKAGE *package)
3658{
3659 MSIFEATURE *feature;
3660
3661 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3662 {
3663 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3664 return TRUE;
3665 }
3666
3667 return FALSE;
3668}
3669
cdb33f8a
JH
3670static BOOL msi_check_unpublish(MSIPACKAGE *package)
3671{
3672 MSIFEATURE *feature;
3673
3674 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3675 {
3676 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3677 return FALSE;
3678 }
3679
3680 return TRUE;
3681}
3682
01eb9300
JH
3683static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3684{
3685 WCHAR patch_squashed[GUID_SIZE];
3686 HKEY patches;
3687 LONG res;
3688 UINT r = ERROR_FUNCTION_FAILED;
3689
3690 static const WCHAR szPatches[] = {'P','a','t','c','h','e','s',0};
3691
3692 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3693 &patches, NULL);
3694 if (res != ERROR_SUCCESS)
3695 return ERROR_FUNCTION_FAILED;
3696
3697 squash_guid(package->patch->patchcode, patch_squashed);
3698
3699 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3700 (const BYTE *)patch_squashed,
3701 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3702 if (res != ERROR_SUCCESS)
3703 goto done;
3704
3705 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3706 (const BYTE *)package->patch->transforms,
3707 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3708 if (res == ERROR_SUCCESS)
3709 r = ERROR_SUCCESS;
3710
3711done:
3712 RegCloseKey(patches);
3713 return r;
3714}
3715
2cf222f9
AS
3716/*
3717 * 99% of the work done here is only done for
3718 * advertised installs. However this is where the
3719 * Icon table is processed and written out
817c5209 3720 * so that is what I am going to do here.
2cf222f9 3721 */
a7a6f5f3 3722static UINT ACTION_PublishProduct(MSIPACKAGE *package)
2cf222f9
AS
3723{
3724 UINT rc;
68b07494 3725 HKEY hukey=0;
ee8b4a01 3726 HKEY hudkey=0;
2cf222f9 3727
a2df31ae
JH
3728 /* FIXME: also need to publish if the product is in advertise mode */
3729 if (!msi_check_publish(package))
3730 return ERROR_SUCCESS;
3731
c965d839 3732 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
70be1e77
JH
3733 &hukey, TRUE);
3734 if (rc != ERROR_SUCCESS)
3735 goto end;
3736
4a9f6995
JH
3737 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3738 NULL, &hudkey, TRUE);
3739 if (rc != ERROR_SUCCESS)
3740 goto end;
6269f00c 3741
cdb33f8a
JH
3742 rc = msi_publish_upgrade_code(package);
3743 if (rc != ERROR_SUCCESS)
3744 goto end;
ebeb5379 3745
01eb9300
JH
3746 if (package->patch)
3747 {
3748 rc = msi_publish_patch(package, hukey, hudkey);
3749 if (rc != ERROR_SUCCESS)
3750 goto end;
3751 }
3752
ebeb5379
JH
3753 rc = msi_publish_product_properties(package, hukey);
3754 if (rc != ERROR_SUCCESS)
337e1e20 3755 goto end;
2cae30b6 3756
2d4e4b6a 3757 rc = msi_publish_sourcelist(package, hukey);
68e6071d
JH
3758 if (rc != ERROR_SUCCESS)
3759 goto end;
5e46fc90 3760
68e6071d 3761 rc = msi_publish_icons(package);
fac97bb8 3762
6269f00c 3763end:
6269f00c 3764 RegCloseKey(hukey);
c18b7755 3765 RegCloseKey(hudkey);
6269f00c 3766
2cf222f9 3767 return rc;
2cf222f9
AS
3768}
3769
aded32f3 3770static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
516a9c70 3771{
5f3ac30b 3772 MSIPACKAGE *package = param;
bf9538f3 3773 LPCWSTR component, section, key, value, identifier, dirproperty;
aded32f3 3774 LPWSTR deformated_section, deformated_key, deformated_value;
bf9538f3
JH
3775 LPWSTR folder, filename, fullname = NULL;
3776 LPCWSTR filenameptr;
aded32f3 3777 MSIRECORD * uirow;
38d67a45
MM
3778 INT action;
3779 MSICOMPONENT *comp;
516a9c70
AS
3780 static const WCHAR szWindowsFolder[] =
3781 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
516a9c70 3782
aded32f3 3783 component = MSI_RecordGetString(row, 8);
38d67a45 3784 comp = get_loaded_component(package,component);
516a9c70 3785
d693f461 3786 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
516a9c70 3787 {
aded32f3
AS
3788 TRACE("Skipping ini file due to disabled component %s\n",
3789 debugstr_w(component));
516a9c70 3790
38d67a45 3791 comp->Action = comp->Installed;
516a9c70 3792
aded32f3
AS
3793 return ERROR_SUCCESS;
3794 }
90c57396 3795
38d67a45 3796 comp->Action = INSTALLSTATE_LOCAL;
90c57396 3797
aded32f3 3798 identifier = MSI_RecordGetString(row,1);
aded32f3
AS
3799 dirproperty = MSI_RecordGetString(row,3);
3800 section = MSI_RecordGetString(row,4);
3801 key = MSI_RecordGetString(row,5);
3802 value = MSI_RecordGetString(row,6);
3803 action = MSI_RecordGetInteger(row,7);
90c57396 3804
aded32f3
AS
3805 deformat_string(package,section,&deformated_section);
3806 deformat_string(package,key,&deformated_key);
3807 deformat_string(package,value,&deformated_value);
516a9c70 3808
bf9538f3
JH
3809 filename = msi_dup_record_field(row, 2);
3810 if (filename && (filenameptr = strchrW(filename, '|')))
3811 filenameptr++;
3812 else
3813 filenameptr = filename;
3814
aded32f3
AS
3815 if (dirproperty)
3816 {
8cedb218 3817 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
516a9c70 3818 if (!folder)
062ad505 3819 folder = msi_dup_property( package, dirproperty );
aded32f3
AS
3820 }
3821 else
062ad505 3822 folder = msi_dup_property( package, szWindowsFolder );
aded32f3
AS
3823
3824 if (!folder)
3825 {
3826 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3827 goto cleanup;
3828 }
516a9c70 3829
bf9538f3 3830 fullname = build_directory_name(2, folder, filenameptr);
516a9c70 3831
aded32f3
AS
3832 if (action == 0)
3833 {
3834 TRACE("Adding value %s to section %s in %s\n",
516a9c70
AS
3835 debugstr_w(deformated_key), debugstr_w(deformated_section),
3836 debugstr_w(fullname));
aded32f3
AS
3837 WritePrivateProfileStringW(deformated_section, deformated_key,
3838 deformated_value, fullname);
3839 }
3840 else if (action == 1)
3841 {
3842 WCHAR returned[10];
3843 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3844 returned, 10, fullname);
3845 if (returned[0] == 0)
516a9c70 3846 {
aded32f3 3847 TRACE("Adding value %s to section %s in %s\n",
516a9c70
AS
3848 debugstr_w(deformated_key), debugstr_w(deformated_section),
3849 debugstr_w(fullname));
3850
aded32f3 3851 WritePrivateProfileStringW(deformated_section, deformated_key,
516a9c70 3852 deformated_value, fullname);
516a9c70 3853 }
aded32f3
AS
3854 }
3855 else if (action == 3)
3856 FIXME("Append to existing section not yet implemented\n");
3857
3858 uirow = MSI_CreateRecord(4);
3859 MSI_RecordSetStringW(uirow,1,identifier);
3860 MSI_RecordSetStringW(uirow,2,deformated_section);
3861 MSI_RecordSetStringW(uirow,3,deformated_key);
3862 MSI_RecordSetStringW(uirow,4,deformated_value);
3863 ui_actiondata(package,szWriteIniValues,uirow);
3864 msiobj_release( &uirow->hdr );
bf9538f3 3865
516a9c70 3866cleanup:
bf9538f3 3867 msi_free(filename);
ee034ba4
MM
3868 msi_free(fullname);
3869 msi_free(folder);
3870 msi_free(deformated_key);
3871 msi_free(deformated_value);
3872 msi_free(deformated_section);
aded32f3
AS
3873 return ERROR_SUCCESS;
3874}
3875
3876static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3877{
3878 UINT rc;
3879 MSIQUERY * view;
3880 static const WCHAR ExecSeqQuery[] =
3881 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3882 '`','I','n','i','F','i','l','e','`',0};
3883
3884 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3885 if (rc != ERROR_SUCCESS)
3886 {
3887 TRACE("no IniFile table\n");
3888 return ERROR_SUCCESS;
516a9c70 3889 }
aded32f3
AS
3890
3891 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
516a9c70
AS
3892 msiobj_release(&view->hdr);
3893 return rc;
3894}
3895
854bfc4b 3896static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
6269f00c 3897{
5f3ac30b 3898 MSIPACKAGE *package = param;
854bfc4b
AS
3899 LPCWSTR filename;
3900 LPWSTR FullName;
e18f8abe 3901 MSIFILE *file;
854bfc4b 3902 DWORD len;
8e233e9b 3903 static const WCHAR ExeStr[] =
c5a1443f
AS
3904 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3905 static const WCHAR close[] = {'\"',0};
2cae30b6
AS
3906 STARTUPINFOW si;
3907 PROCESS_INFORMATION info;
3908 BOOL brc;
d2e48e01
RS
3909 MSIRECORD *uirow;
3910 LPWSTR uipath, p;
2cae30b6
AS
3911
3912 memset(&si,0,sizeof(STARTUPINFOW));
3913
854bfc4b 3914 filename = MSI_RecordGetString(row,1);
e18f8abe 3915 file = get_loaded_file( package, filename );
6269f00c 3916
e18f8abe 3917 if (!file)
6269f00c 3918 {
854bfc4b
AS
3919 ERR("Unable to find file id %s\n",debugstr_w(filename));
3920 return ERROR_SUCCESS;
6269f00c
AS
3921 }
3922
e18f8abe 3923 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
6269f00c 3924
ee034ba4 3925 FullName = msi_alloc(len*sizeof(WCHAR));
854bfc4b 3926 strcpyW(FullName,ExeStr);
e18f8abe 3927 strcatW( FullName, file->TargetPath );
854bfc4b 3928 strcatW(FullName,close);
6269f00c 3929
854bfc4b
AS
3930 TRACE("Registering %s\n",debugstr_w(FullName));
3931 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3932 &si, &info);
6269f00c 3933
854bfc4b 3934 if (brc)
cda469c8
RS
3935 {
3936 CloseHandle(info.hThread);
854bfc4b 3937 msi_dialog_check_messages(info.hProcess);
cda469c8
RS
3938 CloseHandle(info.hProcess);
3939 }
6269f00c 3940
ee034ba4 3941 msi_free(FullName);
d2e48e01
RS
3942
3943 /* the UI chunk */
3944 uirow = MSI_CreateRecord( 2 );
3945 uipath = strdupW( file->TargetPath );
3946 p = strrchrW(uipath,'\\');
3947 if (p)
220f93db
RS
3948 p[0]=0;
3949 MSI_RecordSetStringW( uirow, 1, &p[1] );
d2e48e01
RS
3950 MSI_RecordSetStringW( uirow, 2, uipath);
3951 ui_actiondata( package, szSelfRegModules, uirow);
3952 msiobj_release( &uirow->hdr );
3953 msi_free( uipath );
3954 /* FIXME: call ui_progress? */
3955
854bfc4b
AS
3956 return ERROR_SUCCESS;
3957}
6269f00c 3958
854bfc4b
AS
3959static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3960{
3961 UINT rc;
3962 MSIQUERY * view;
3963 static const WCHAR ExecSeqQuery[] =
3964 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3965 '`','S','e','l','f','R','e','g','`',0};
6269f00c 3966
854bfc4b
AS
3967 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3968 if (rc != ERROR_SUCCESS)
3969 {
3970 TRACE("no SelfReg table\n");
3971 return ERROR_SUCCESS;
6269f00c 3972 }
854bfc4b
AS
3973
3974 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
6269f00c 3975 msiobj_release(&view->hdr);
854bfc4b
AS
3976
3977 return ERROR_SUCCESS;
6269f00c
AS
3978}
3979
3980static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3981{
1da2858c 3982 MSIFEATURE *feature;
6269f00c 3983 UINT rc;
2a180e06 3984 HKEY hkey;
be759ddd 3985 HKEY userdata = NULL;
6ac08161
JH
3986
3987 if (!msi_check_publish(package))
3988 return ERROR_SUCCESS;
3989
0c01c586
JH
3990 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3991 &hkey, TRUE);
3992 if (rc != ERROR_SUCCESS)
3993 goto end;
3994
e3074348
JH
3995 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3996 &userdata, TRUE);
3997 if (rc != ERROR_SUCCESS)
3998 goto end;
9f11a5a8 3999
6269f00c 4000 /* here the guids are base 85 encoded */
1da2858c 4001 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
6269f00c 4002 {
3f2d5d7f 4003 ComponentList *cl;
6269f00c
AS
4004 LPWSTR data = NULL;
4005 GUID clsid;
6269f00c 4006 INT size;
b39d8fc2 4007 BOOL absent = FALSE;
d2e48e01 4008 MSIRECORD *uirow;
6269f00c 4009
1da2858c
MM
4010 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
4011 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
4012 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
b39d8fc2 4013 absent = TRUE;
b6bc6aa6 4014
3f2d5d7f 4015 size = 1;
1da2858c 4016 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3f2d5d7f
MM
4017 {
4018 size += 21;
4019 }
79ca56cd 4020 if (feature->Feature_Parent)
1da2858c 4021 size += strlenW( feature->Feature_Parent )+2;
6269f00c 4022
ee034ba4 4023 data = msi_alloc(size * sizeof(WCHAR));
6269f00c
AS
4024
4025 data[0] = 0;
1da2858c 4026 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
6269f00c 4027 {
38d67a45 4028 MSICOMPONENT* component = cl->component;
6269f00c 4029 WCHAR buf[21];
3f2d5d7f 4030
3a94011a 4031 buf[0] = 0;
efcc1ec5 4032 if (component->ComponentId)
c5a1443f 4033 {
3f2d5d7f
MM
4034 TRACE("From %s\n",debugstr_w(component->ComponentId));
4035 CLSIDFromString(component->ComponentId, &clsid);
c5a1443f
AS
4036 encode_base85_guid(&clsid,buf);
4037 TRACE("to %s\n",debugstr_w(buf));
4038 strcatW(data,buf);
4039 }
6269f00c 4040 }
9f11a5a8 4041
79ca56cd 4042 if (feature->Feature_Parent)
6269f00c
AS
4043 {
4044 static const WCHAR sep[] = {'\2',0};
4045 strcatW(data,sep);
1da2858c 4046 strcatW(data,feature->Feature_Parent);
6269f00c
AS
4047 }
4048
9f11a5a8 4049 msi_reg_set_val_str( userdata, feature->Feature, data );
ee034ba4 4050 msi_free(data);
6269f00c 4051
79ca56cd
MM
4052 size = 0;
4053 if (feature->Feature_Parent)
4054 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
b39d8fc2
AS
4055 if (!absent)
4056 {
06bf8ea2
AJ
4057 static const WCHAR emptyW[] = {0};
4058 size += sizeof(WCHAR);
2a180e06 4059 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
06bf8ea2 4060 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
b39d8fc2
AS
4061 }
4062 else
4063 {
79ca56cd 4064 size += 2*sizeof(WCHAR);
ee034ba4 4065 data = msi_alloc(size);
b39d8fc2 4066 data[0] = 0x6;
79ca56cd
MM
4067 data[1] = 0;
4068 if (feature->Feature_Parent)
4069 strcpyW( &data[1], feature->Feature_Parent );
2a180e06 4070 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
16466af7 4071 (LPBYTE)data,size);
ee034ba4 4072 msi_free(data);
b39d8fc2 4073 }
d2e48e01
RS
4074
4075 /* the UI chunk */
4076 uirow = MSI_CreateRecord( 1 );
4077 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4078 ui_actiondata( package, szPublishFeatures, uirow);
4079 msiobj_release( &uirow->hdr );
4080 /* FIXME: call ui_progress? */
6269f00c
AS
4081 }
4082
6269f00c 4083end:
2a180e06
JH
4084 RegCloseKey(hkey);
4085 RegCloseKey(userdata);
6269f00c
AS
4086 return rc;
4087}
4088
6ac08161
JH
4089static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4090{
4091 UINT r;
4092 HKEY hkey;
4093
4094 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4095
0c01c586
JH
4096 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4097 &hkey, FALSE);
6ac08161
JH
4098 if (r == ERROR_SUCCESS)
4099 {
4100 RegDeleteValueW(hkey, feature->Feature);
4101 RegCloseKey(hkey);
4102 }
4103
e3074348
JH
4104 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4105 &hkey, FALSE);
6ac08161
JH
4106 if (r == ERROR_SUCCESS)
4107 {
4108 RegDeleteValueW(hkey, feature->Feature);
4109 RegCloseKey(hkey);
4110 }
4111
4112 return ERROR_SUCCESS;
4113}
4114
4115static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4116{
4117 MSIFEATURE *feature;
4118
ccdf578b 4119 if (!msi_check_unpublish(package))
6ac08161
JH
4120 return ERROR_SUCCESS;
4121
4122 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4123 {
4124 msi_unpublish_feature(package, feature);
4125 }
4126
4127 return ERROR_SUCCESS;
4128}
4129
5f83069b 4130static UINT msi_get_local_package_name( LPWSTR path )
61f24a4c 4131{
5f83069b
MM
4132 static const WCHAR szInstaller[] = {
4133 '\\','I','n','s','t','a','l','l','e','r','\\',0};
4134 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
4135 DWORD time, len, i;
4136 HANDLE handle;
4137
4138 time = GetTickCount();
4139 GetWindowsDirectoryW( path, MAX_PATH );
4140 lstrcatW( path, szInstaller );
4141 CreateDirectoryW( path, NULL );
4142
4143 len = lstrlenW(path);
4144 for (i=0; i<0x10000; i++)
61f24a4c 4145 {
5f83069b
MM
4146 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
4147 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
4148 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
61f24a4c
MM
4149 if (handle != INVALID_HANDLE_VALUE)
4150 {
4151 CloseHandle(handle);
4152 break;
4153 }
4154 if (GetLastError() != ERROR_FILE_EXISTS &&
4155 GetLastError() != ERROR_SHARING_VIOLATION)
5f83069b
MM
4156 return ERROR_FUNCTION_FAILED;
4157 }
4158
4159 return ERROR_SUCCESS;
4160}
61f24a4c 4161
5f83069b
MM
4162static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
4163{
5f83069b 4164 WCHAR packagefile[MAX_PATH];
5f83069b
MM
4165 UINT r;
4166
4167 r = msi_get_local_package_name( packagefile );
4168 if (r != ERROR_SUCCESS)
4169 return r;
61f24a4c
MM
4170
4171 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
4172
c37849ad 4173 r = CopyFileW( package->db->path, packagefile, FALSE);
61f24a4c
MM
4174
4175 if (!r)
4176 {
f1d4646a 4177 ERR("Unable to copy package (%s -> %s) (error %d)\n",
c37849ad 4178 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
61f24a4c
MM
4179 return ERROR_FUNCTION_FAILED;
4180 }
4181
61f24a4c 4182 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
fc6b9dd4 4183
61f24a4c
MM
4184 return ERROR_SUCCESS;
4185}
4186
45de896a 4187static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
ba293eef
MM
4188{
4189 LPWSTR prop, val, key;
45de896a
JH
4190 SYSTEMTIME systime;
4191 DWORD size, langid;
4192 WCHAR date[9];
4193 LPWSTR buffer;
4194
4195 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4196 static const WCHAR szWindowsInstaller[] =
4197 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4198 static const WCHAR modpath_fmt[] =
4199 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4200 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4201 static const WCHAR szModifyPath[] =
4202 {'M','o','d','i','f','y','P','a','t','h',0};
4203 static const WCHAR szUninstallString[] =
4204 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4205 static const WCHAR szEstimatedSize[] =
4206 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4207 static const WCHAR szProductLanguage[] =
4208 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4209 static const WCHAR szProductVersion[] =
4210 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4211 static const WCHAR szProductName[] =
4212 {'P','r','o','d','u','c','t','N','a','m','e',0};
4213 static const WCHAR szDisplayName[] =
4214 {'D','i','s','p','l','a','y','N','a','m','e',0};
4215 static const WCHAR szDisplayVersion[] =
4216 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4217 static const WCHAR szManufacturer[] =
4218 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4219
ba293eef
MM
4220 static const LPCSTR propval[] = {
4221 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4222 "ARPCONTACT", "Contact",
4223 "ARPCOMMENTS", "Comments",
4224 "ProductName", "DisplayName",
4225 "ProductVersion", "DisplayVersion",
4226 "ARPHELPLINK", "HelpLink",
4227 "ARPHELPTELEPHONE", "HelpTelephone",
4228 "ARPINSTALLLOCATION", "InstallLocation",
4229 "SourceDir", "InstallSource",
4230 "Manufacturer", "Publisher",
4231 "ARPREADME", "Readme",
4232 "ARPSIZE", "Size",
4233 "ARPURLINFOABOUT", "URLInfoAbout",
4234 "ARPURLUPDATEINFO", "URLUpdateInfo",
4235 NULL,
4236 };
4237 const LPCSTR *p = propval;
4238
45de896a 4239 while (*p)
ba293eef 4240 {
45de896a
JH
4241 prop = strdupAtoW(*p++);
4242 key = strdupAtoW(*p++);
4243 val = msi_dup_property(package, prop);
4244 msi_reg_set_val_str(hkey, key, val);
ba293eef
MM
4245 msi_free(val);
4246 msi_free(key);
4247 msi_free(prop);
4248 }
45de896a
JH
4249
4250 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4251
4252 size = deformat_string(package, modpath_fmt, &buffer);
4253 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4254 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4255 msi_free(buffer);
4256
4257 /* FIXME: Write real Estimated Size when we have it */
4258 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4259
4260 buffer = msi_dup_property(package, szProductName);
4261 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4262 msi_free(buffer);
4263
4264 buffer = msi_dup_property(package, cszSourceDir);
4265 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4266 msi_free(buffer);
4267
4268 buffer = msi_dup_property(package, szManufacturer);
4269 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4270 msi_free(buffer);
4271
4272 GetLocalTime(&systime);
4273 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4274 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4275
4276 langid = msi_get_property_int(package, szProductLanguage, 0);
4277 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4278
4279 buffer = msi_dup_property(package, szProductVersion);
4280 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4281 if (buffer)
4282 {
4283 DWORD verdword = msi_version_str_to_dword(buffer);
4284
4285 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4286 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4287 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4288 msi_free(buffer);
4289 }
4290
ba293eef
MM
4291 return ERROR_SUCCESS;
4292}
4293
2cae30b6
AS
4294static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4295{
45de896a
JH
4296 WCHAR squashed_pc[SQUISH_GUID_SIZE];
4297 LPWSTR upgrade_code;
4298 HKEY hkey, props;
4299 HKEY upgrade;
ba293eef 4300 UINT rc;
e9db87b9 4301
45de896a
JH
4302 static const WCHAR szUpgradeCode[] = {
4303 'U','p','g','r','a','d','e','C','o','d','e',0};
0e44e090
JH
4304
4305 /* FIXME: also need to publish if the product is in advertise mode */
4306 if (!msi_check_publish(package))
4307 return ERROR_SUCCESS;
2cae30b6 4308
45de896a 4309 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
2cae30b6 4310 if (rc != ERROR_SUCCESS)
ba293eef 4311 return rc;
2cae30b6 4312
b5e3e19a
JH
4313 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4314 NULL, &props, TRUE);
4315 if (rc != ERROR_SUCCESS)
4316 goto done;
d52f48fe 4317
45de896a 4318 msi_make_package_local(package, props);
d52f48fe 4319
45de896a
JH
4320 rc = msi_publish_install_properties(package, hkey);
4321 if (rc != ERROR_SUCCESS)
4322 goto done;
e9db87b9 4323
45de896a
JH
4324 rc = msi_publish_install_properties(package, props);
4325 if (rc != ERROR_SUCCESS)
4326 goto done;
4db02cdb 4327
45de896a 4328 upgrade_code = msi_dup_property(package, szUpgradeCode);
36a01505
AS
4329 if (upgrade_code)
4330 {
45de896a
JH
4331 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4332 squash_guid(package->ProductCode, squashed_pc);
4333 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4334 RegCloseKey(upgrade);
ee034ba4 4335 msi_free(upgrade_code);
36a01505 4336 }
bcba82dc 4337
45de896a 4338done:
2cae30b6 4339 RegCloseKey(hkey);
2cae30b6
AS
4340
4341 return ERROR_SUCCESS;
4342}
4343
4344static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4345{
a977b2c3 4346 return execute_script(package,INSTALL_SCRIPT);
2cae30b6
AS
4347}
4348
624bbbe7
JH
4349static UINT msi_unpublish_product(MSIPACKAGE *package)
4350{
cdb33f8a 4351 LPWSTR upgrade;
624bbbe7
JH
4352 LPWSTR remove = NULL;
4353 LPWSTR *features = NULL;
4354 BOOL full_uninstall = TRUE;
4355 MSIFEATURE *feature;
4356
4357 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4358 static const WCHAR szAll[] = {'A','L','L',0};
cdb33f8a
JH
4359 static const WCHAR szUpgradeCode[] =
4360 {'U','p','g','r','a','d','e','C','o','d','e',0};
624bbbe7
JH
4361
4362 remove = msi_dup_property(package, szRemove);
4363 if (!remove)
4364 return ERROR_SUCCESS;
4365
4366 features = msi_split_string(remove, ',');
4367 if (!features)
4368 {
4369 msi_free(remove);
4370 ERR("REMOVE feature list is empty!\n");
4371 return ERROR_FUNCTION_FAILED;
4372 }
4373
4374 if (!lstrcmpW(features[0], szAll))
4375 full_uninstall = TRUE;
4376 else
4377 {
4378 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4379 {
4380 if (feature->Action != INSTALLSTATE_ABSENT)
4381 full_uninstall = FALSE;
4382 }
4383 }
4384
4385 if (!full_uninstall)
4386 goto done;
4387
4388 MSIREG_DeleteProductKey(package->ProductCode);
624bbbe7 4389 MSIREG_DeleteUserDataProductKey(package->ProductCode);
f6b27673 4390 MSIREG_DeleteUninstallKey(package->ProductCode);
624bbbe7 4391
38106ac2
JH
4392 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4393 {
4394 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4395 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4396 }
4397 else
4398 {
4399 MSIREG_DeleteUserProductKey(package->ProductCode);
4400 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4401 }
4402
cdb33f8a
JH
4403 upgrade = msi_dup_property(package, szUpgradeCode);
4404 if (upgrade)
4405 {
4406 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4407 msi_free(upgrade);
4408 }
4409
624bbbe7
JH
4410done:
4411 msi_free(remove);
4412 msi_free(features);
4413 return ERROR_SUCCESS;
4414}
4415
2cae30b6
AS
4416static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4417{
9cd707da
AS
4418 UINT rc;
4419
624bbbe7
JH
4420 rc = msi_unpublish_product(package);
4421 if (rc != ERROR_SUCCESS)
4422 return rc;
4423
1ccf9449 4424 /* turn off scheduling */
9cd707da
AS
4425 package->script->CurrentlyScripting= FALSE;
4426
54c67dd1 4427 /* first do the same as an InstallExecute */
9cd707da
AS
4428 rc = ACTION_InstallExecute(package);
4429 if (rc != ERROR_SUCCESS)
4430 return rc;
54c67dd1
AS
4431
4432 /* then handle Commit Actions */
9cd707da 4433 rc = execute_script(package,COMMIT_SCRIPT);
2cae30b6 4434
9cd707da 4435 return rc;
2cae30b6
AS
4436}
4437
c2e91588 4438UINT ACTION_ForceReboot(MSIPACKAGE *package)
2cae30b6
AS
4439{
4440 static const WCHAR RunOnce[] = {
4441 'S','o','f','t','w','a','r','e','\\',
4442 'M','i','c','r','o','s','o','f','t','\\',
4443 'W','i','n','d','o','w','s','\\',
4444 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
09b8264f 4445 'R','u','n','O','n','c','e',0};
2cae30b6
AS
4446 static const WCHAR InstallRunOnce[] = {
4447 'S','o','f','t','w','a','r','e','\\',
4448 'M','i','c','r','o','s','o','f','t','\\',
4449 'W','i','n','d','o','w','s','\\',
4450 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4451 'I','n','s','t','a','l','l','e','r','\\',
09b8264f 4452 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
2cae30b6
AS
4453
4454 static const WCHAR msiexec_fmt[] = {
014ad3ba 4455 '%','s',
2cae30b6
AS
4456 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4457 '\"','%','s','\"',0};
4458 static const WCHAR install_fmt[] = {
4459 '/','I',' ','\"','%','s','\"',' ',
4460 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4461 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
014ad3ba 4462 WCHAR buffer[256], sysdir[MAX_PATH];
adaef111 4463 HKEY hkey;
4db02cdb 4464 WCHAR squished_pc[100];
2cae30b6 4465
adaef111 4466 squash_guid(package->ProductCode,squished_pc);
2cae30b6 4467
014ad3ba 4468 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
2cae30b6 4469 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
014ad3ba
JL
4470 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4471 squished_pc);
2cae30b6 4472
4db02cdb 4473 msi_reg_set_val_str( hkey, squished_pc, buffer );
2cae30b6
AS
4474 RegCloseKey(hkey);
4475
4476 TRACE("Reboot command %s\n",debugstr_w(buffer));
4477
4478 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
adaef111 4479 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
b6bc6aa6 4480
4db02cdb 4481 msi_reg_set_val_str( hkey, squished_pc, buffer );
2cae30b6
AS
4482 RegCloseKey(hkey);
4483
68b07494 4484 return ERROR_INSTALL_SUSPEND;
2cae30b6
AS
4485}
4486
563a50ab 4487static UINT ACTION_ResolveSource(MSIPACKAGE* package)
90c57396 4488{
b921118f 4489 DWORD attrib;
94d6818c 4490 UINT rc;
fc564239 4491
90c57396 4492 /*
fc564239
MM
4493 * We are currently doing what should be done here in the top level Install
4494 * however for Administrative and uninstalls this step will be needed
90c57396 4495 */
94d6818c
AS
4496 if (!package->PackagePath)
4497 return ERROR_SUCCESS;
4498
c777d309 4499 msi_set_sourcedir_props(package, TRUE);
c5075435 4500
e28cedf6 4501 attrib = GetFileAttributesW(package->db->path);
94d6818c
AS
4502 if (attrib == INVALID_FILE_ATTRIBUTES)
4503 {
4504 LPWSTR prompt;
4505 LPWSTR msg;
4506 DWORD size = 0;
4507
4508 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
82517d6d 4509 package->Context, MSICODE_PRODUCT,
94d6818c
AS
4510 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4511 if (rc == ERROR_MORE_DATA)
4512 {
ee034ba4 4513 prompt = msi_alloc(size * sizeof(WCHAR));
94d6818c 4514 MsiSourceListGetInfoW(package->ProductCode, NULL,
82517d6d 4515 package->Context, MSICODE_PRODUCT,
94d6818c
AS
4516 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4517 }
4518 else
e28cedf6 4519 prompt = strdupW(package->db->path);
94d6818c
AS
4520
4521 msg = generate_error_string(package,1302,1,prompt);
4522 while(attrib == INVALID_FILE_ATTRIBUTES)
4523 {
4524 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4525 if (rc == IDCANCEL)
4526 {
4527 rc = ERROR_INSTALL_USEREXIT;
4528 break;
4529 }
e28cedf6 4530 attrib = GetFileAttributesW(package->db->path);
94d6818c 4531 }
ee034ba4 4532 msi_free(prompt);
94d6818c
AS
4533 rc = ERROR_SUCCESS;
4534 }
4535 else
4536 return ERROR_SUCCESS;
4537
4538 return rc;
90c57396
AS
4539}
4540
c7e88e08
AS
4541static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4542{
c7e88e08
AS
4543 HKEY hkey=0;
4544 LPWSTR buffer;
c7e88e08
AS
4545 LPWSTR productid;
4546 UINT rc,i;
c7e88e08
AS
4547
4548 static const WCHAR szPropKeys[][80] =
4549 {
8e233e9b
AS
4550 {'P','r','o','d','u','c','t','I','D',0},
4551 {'U','S','E','R','N','A','M','E',0},
4552 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4553 {0},
c7e88e08
AS
4554 };
4555
4556 static const WCHAR szRegKeys[][80] =
4557 {
8e233e9b
AS
4558 {'P','r','o','d','u','c','t','I','D',0},
4559 {'R','e','g','O','w','n','e','r',0},
4560 {'R','e','g','C','o','m','p','a','n','y',0},
4561 {0},
c7e88e08
AS
4562 };
4563
d52f48fe
JH
4564 if (msi_check_unpublish(package))
4565 {
4566 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4567 return ERROR_SUCCESS;
4568 }
4569
062ad505 4570 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
c7e88e08
AS
4571 if (!productid)
4572 return ERROR_SUCCESS;
4573
b5e3e19a
JH
4574 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4575 NULL, &hkey, TRUE);
c7e88e08
AS
4576 if (rc != ERROR_SUCCESS)
4577 goto end;
4578
67189f9d 4579 for( i = 0; szPropKeys[i][0]; i++ )
c7e88e08 4580 {
062ad505 4581 buffer = msi_dup_property( package, szPropKeys[i] );
4db02cdb 4582 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
ee034ba4 4583 msi_free( buffer );
c7e88e08
AS
4584 }
4585
4586end:
ee034ba4 4587 msi_free(productid);
c7e88e08
AS
4588 RegCloseKey(hkey);
4589
d2e48e01
RS
4590 /* FIXME: call ui_actiondata */
4591
d52f48fe 4592 return rc;
c7e88e08
AS
4593}
4594
b6bc6aa6
AS
4595
4596static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4597{
4598 UINT rc;
25f1e75d 4599
c9802931 4600 package->script->InWhatSequence |= SEQUENCE_EXEC;
b39d8fc2 4601 rc = ACTION_ProcessExecSequence(package,FALSE);
b6bc6aa6
AS
4602 return rc;
4603}
4604
0af2487a 4605
072c5e56
AS
4606static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4607{
5f3ac30b 4608 MSIPACKAGE *package = param;
09b0abaa
AS
4609 LPCWSTR compgroupid=NULL;
4610 LPCWSTR feature=NULL;
4611 LPCWSTR text = NULL;
4612 LPCWSTR qualifier = NULL;
4613 LPCWSTR component = NULL;
6f43c18f
AS
4614 LPWSTR advertise = NULL;
4615 LPWSTR output = NULL;
072c5e56
AS
4616 HKEY hkey;
4617 UINT rc = ERROR_SUCCESS;
38d67a45 4618 MSICOMPONENT *comp;
072c5e56 4619 DWORD sz = 0;
d2e48e01 4620 MSIRECORD *uirow;
b39d8fc2 4621
09b0abaa 4622 component = MSI_RecordGetString(rec,3);
38d67a45
MM
4623 comp = get_loaded_component(package,component);
4624
d693f461
MM
4625 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4626 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4627 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
b39d8fc2
AS
4628 {
4629 TRACE("Skipping: Component %s not scheduled for install\n",
4630 debugstr_w(component));
6f43c18f 4631
b39d8fc2
AS
4632 return ERROR_SUCCESS;
4633 }
072c5e56 4634
09b0abaa 4635 compgroupid = MSI_RecordGetString(rec,1);
d2e48e01 4636 qualifier = MSI_RecordGetString(rec,2);
072c5e56
AS
4637
4638 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4639 if (rc != ERROR_SUCCESS)
4640 goto end;
4641
09b0abaa 4642 text = MSI_RecordGetString(rec,4);
09b0abaa 4643 feature = MSI_RecordGetString(rec,5);
072c5e56 4644
38d67a45 4645 advertise = create_component_advertise_string(package, comp, feature);
6f43c18f
AS
4646
4647 sz = strlenW(advertise);
072c5e56 4648
072c5e56
AS
4649 if (text)
4650 sz += lstrlenW(text);
072c5e56
AS
4651
4652 sz+=3;
4653 sz *= sizeof(WCHAR);
4654
3a94011a 4655 output = msi_alloc_zero(sz);
6f43c18f 4656 strcpyW(output,advertise);
470f23d4 4657 msi_free(advertise);
072c5e56
AS
4658
4659 if (text)
4660 strcatW(output,text);
4661
4db02cdb 4662 msi_reg_set_val_multi_str( hkey, qualifier, output );
072c5e56
AS
4663
4664end:
4665 RegCloseKey(hkey);
ee034ba4 4666 msi_free(output);
d2e48e01
RS
4667
4668 /* the UI chunk */
4669 uirow = MSI_CreateRecord( 2 );
4670 MSI_RecordSetStringW( uirow, 1, compgroupid );
4671 MSI_RecordSetStringW( uirow, 2, qualifier);
4672 ui_actiondata( package, szPublishComponents, uirow);
4673 msiobj_release( &uirow->hdr );
4674 /* FIXME: call ui_progress? */
4675
072c5e56
AS
4676 return rc;
4677}
4678
4679/*
4680 * At present I am ignorning the advertised components part of this and only
4681 * focusing on the qualified component sets
4682 */
4683static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4684{
4685 UINT rc;
4686 MSIQUERY * view;
4687 static const WCHAR ExecSeqQuery[] =
4688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
98e38082
AS
4689 '`','P','u','b','l','i','s','h',
4690 'C','o','m','p','o','n','e','n','t','`',0};
072c5e56
AS
4691
4692 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4693 if (rc != ERROR_SUCCESS)
4694 return ERROR_SUCCESS;
4695
4696 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4697 msiobj_release(&view->hdr);
4698
4699 return rc;
4700}
202166c3 4701
9bc12ade
JH
4702static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4703{
5f3ac30b 4704 MSIPACKAGE *package = param;
9bc12ade
JH
4705 MSIRECORD *row;
4706 MSIFILE *file;
4707 SC_HANDLE hscm, service = NULL;
de4cab20 4708 LPCWSTR comp, depends, pass;
db71fb15 4709 LPWSTR name = NULL, disp = NULL;
9bc12ade
JH
4710 LPCWSTR load_order, serv_name, key;
4711 DWORD serv_type, start_type;
4712 DWORD err_control;
4713
4714 static const WCHAR query[] =
4715 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4716 '`','C','o','m','p','o','n','e','n','t','`',' ',
4717 'W','H','E','R','E',' ',
4718 '`','C','o','m','p','o','n','e','n','t','`',' ',
4719 '=','\'','%','s','\'',0};
4720
4721 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4722 if (!hscm)
4723 {
4724 ERR("Failed to open the SC Manager!\n");
4725 goto done;
4726 }
4727
4728 start_type = MSI_RecordGetInteger(rec, 5);
4729 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4730 goto done;
4731
4732 depends = MSI_RecordGetString(rec, 8);
4733 if (depends && *depends)
4734 FIXME("Dependency list unhandled!\n");
4735
de4cab20
JH
4736 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4737 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
9bc12ade
JH
4738 serv_type = MSI_RecordGetInteger(rec, 4);
4739 err_control = MSI_RecordGetInteger(rec, 6);
4740 load_order = MSI_RecordGetString(rec, 7);
4741 serv_name = MSI_RecordGetString(rec, 9);
4742 pass = MSI_RecordGetString(rec, 10);
4743 comp = MSI_RecordGetString(rec, 12);
4744
4745 /* fetch the service path */
4746 row = MSI_QueryGetRecord(package->db, query, comp);
4747 if (!row)
4748 {
4749 ERR("Control query failed!\n");
4750 goto done;
4751 }
4752
4753 key = MSI_RecordGetString(row, 6);
9bc12ade
JH
4754
4755 file = get_loaded_file(package, key);
b6cfc405 4756 msiobj_release(&row->hdr);
9bc12ade
JH
4757 if (!file)
4758 {
4759 ERR("Failed to load the service file\n");
4760 goto done;
4761 }
4762
4763 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4764 start_type, err_control, file->TargetPath,
4765 load_order, NULL, NULL, serv_name, pass);
4766 if (!service)
4767 {
4768 if (GetLastError() != ERROR_SERVICE_EXISTS)
4769 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4770 }
4771
4772done:
4773 CloseServiceHandle(service);
4774 CloseServiceHandle(hscm);
de4cab20
JH
4775 msi_free(name);
4776 msi_free(disp);
9bc12ade
JH
4777
4778 return ERROR_SUCCESS;
4779}
4780
4781static UINT ACTION_InstallServices( MSIPACKAGE *package )
4782{
4783 UINT rc;
4784 MSIQUERY * view;
4785 static const WCHAR ExecSeqQuery[] =
4786 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4787 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4788
4789 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4790 if (rc != ERROR_SUCCESS)
4791 return ERROR_SUCCESS;
4792
4793 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4794 msiobj_release(&view->hdr);
4795
4796 return rc;
4797}
4798
58bb3571 4799/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
cf8e9e33 4800static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
58bb3571 4801{
99ad76c3 4802 LPCWSTR *vector, *temp_vector;
58bb3571
JH
4803 LPWSTR p, q;
4804 DWORD sep_len;
4805
4806 static const WCHAR separator[] = {'[','~',']',0};
4807
4808 *numargs = 0;
4809 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4810
4811 if (!args)
4812 return NULL;
4813
4814 vector = msi_alloc(sizeof(LPWSTR));
4815 if (!vector)
4816 return NULL;
4817
4818 p = args;
4819 do
4820 {
4821 (*numargs)++;
4822 vector[*numargs - 1] = p;
4823
4824 if ((q = strstrW(p, separator)))
4825 {
4826 *q = '\0';
4827
99ad76c3
LD
4828 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4829 if (!temp_vector)
4830 {
4831 msi_free(vector);
58bb3571 4832 return NULL;
99ad76c3
LD
4833 }
4834 vector = temp_vector;
58bb3571
JH
4835
4836 p = q + sep_len;
4837 }
4838 } while (q);
4839
4840 return vector;
4841}
4842
58bb3571
JH
4843static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4844{
5f3ac30b 4845 MSIPACKAGE *package = param;
58bb3571
JH
4846 MSICOMPONENT *comp;
4847 SC_HANDLE scm, service = NULL;
4848 LPCWSTR name, *vector = NULL;
4849 LPWSTR args;
4850 DWORD event, numargs;
4851 UINT r = ERROR_FUNCTION_FAILED;
4852
eec9bbb1 4853 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
58bb3571
JH
4854 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4855 return ERROR_SUCCESS;
4856
4857 name = MSI_RecordGetString(rec, 2);
4858 event = MSI_RecordGetInteger(rec, 3);
4859 args = strdupW(MSI_RecordGetString(rec, 4));
4860
4861 if (!(event & msidbServiceControlEventStart))
4862 return ERROR_SUCCESS;
4863
4864 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4865 if (!scm)
4866 {
4867 ERR("Failed to open the service control manager\n");
4868 goto done;
4869 }
4870
4871 service = OpenServiceW(scm, name, SERVICE_START);
4872 if (!service)
4873 {
aab5e585 4874 ERR("Failed to open service %s\n", debugstr_w(name));
58bb3571
JH
4875 goto done;
4876 }
4877
cf8e9e33 4878 vector = msi_service_args_to_vector(args, &numargs);
58bb3571
JH
4879
4880 if (!StartServiceW(service, numargs, vector))
4881 {
aab5e585 4882 ERR("Failed to start service %s\n", debugstr_w(name));
58bb3571
JH
4883 goto done;
4884 }
4885
4886 r = ERROR_SUCCESS;
4887
4888done:
4889 CloseServiceHandle(service);
4890 CloseServiceHandle(scm);
4891
4892 msi_free(args);
4893 msi_free(vector);
4894 return r;
4895}
4896
4897static UINT ACTION_StartServices( MSIPACKAGE *package )
4898{
4899 UINT rc;
4900 MSIQUERY *view;
4901
4902 static const WCHAR query[] = {
4903 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4904 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4905
4906 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4907 if (rc != ERROR_SUCCESS)
4908 return ERROR_SUCCESS;
4909
4910 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4911 msiobj_release(&view->hdr);
4912
4913 return rc;
4914}
4915
fb508ff8
JH
4916static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4917{
4918 DWORD i, needed, count;
4919 ENUM_SERVICE_STATUSW *dependencies;
4920 SERVICE_STATUS ss;
4921 SC_HANDLE depserv;
4922
4923 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4924 0, &needed, &count))
4925 return TRUE;
4926
4927 if (GetLastError() != ERROR_MORE_DATA)
4928 return FALSE;
4929
4930 dependencies = msi_alloc(needed);
4931 if (!dependencies)
4932 return FALSE;
4933
4934 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4935 needed, &needed, &count))
4936 goto error;
4937
4938 for (i = 0; i < count; i++)
4939 {
4940 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4941 SERVICE_STOP | SERVICE_QUERY_STATUS);
4942 if (!depserv)
4943 goto error;
4944
4945 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4946 goto error;
4947 }
4948
4949 return TRUE;
4950
4951error:
4952 msi_free(dependencies);
4953 return FALSE;
4954}
4955
4956static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4957{
5f3ac30b 4958 MSIPACKAGE *package = param;
fb508ff8
JH
4959 MSICOMPONENT *comp;
4960 SERVICE_STATUS status;
4961 SERVICE_STATUS_PROCESS ssp;
4962 SC_HANDLE scm = NULL, service = NULL;
4963 LPWSTR name, args;
4964 DWORD event, needed;
4965
4966 event = MSI_RecordGetInteger(rec, 3);
4967 if (!(event & msidbServiceControlEventStop))
4968 return ERROR_SUCCESS;
4969
4970 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4971 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4972 return ERROR_SUCCESS;
4973
4974 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4975 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4976 args = strdupW(MSI_RecordGetString(rec, 4));
4977
4978 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4979 if (!scm)
4980 {
4981 WARN("Failed to open the SCM: %d\n", GetLastError());
4982 goto done;
4983 }
4984
4985 service = OpenServiceW(scm, name,
4986 SERVICE_STOP |
4987 SERVICE_QUERY_STATUS |
4988 SERVICE_ENUMERATE_DEPENDENTS);
4989 if (!service)
4990 {
4991 WARN("Failed to open service (%s): %d\n",
4992 debugstr_w(name), GetLastError());
4993 goto done;
4994 }
4995
4996 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4997 sizeof(SERVICE_STATUS_PROCESS), &needed))
4998 {
4999 WARN("Failed to query service status (%s): %d\n",
5000 debugstr_w(name), GetLastError());
5001 goto done;
5002 }
5003
5004 if (ssp.dwCurrentState == SERVICE_STOPPED)
5005 goto done;
5006
5007 stop_service_dependents(scm, service);
5008
ddfefc03 5009 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
fb508ff8
JH
5010 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5011
5012done:
5013 CloseServiceHandle(service);
5014 CloseServiceHandle(scm);
5015 msi_free(name);
5016 msi_free(args);
5017
5018 return ERROR_SUCCESS;
5019}
5020
5021static UINT ACTION_StopServices( MSIPACKAGE *package )
5022{
5023 UINT rc;
5024 MSIQUERY *view;
5025
5026 static const WCHAR query[] = {
5027 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5028 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5029
5030 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5031 if (rc != ERROR_SUCCESS)
5032 return ERROR_SUCCESS;
5033
5034 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5035 msiobj_release(&view->hdr);
5036
5037 return rc;
5038}
5039
d3bec325
JH
5040static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5041{
5042 MSIFILE *file;
5043
5044 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5045 {
5046 if (!lstrcmpW(file->File, filename))
5047 return file;
5048 }
5049
5050 return NULL;
5051}
5052
5053static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5054{
5f3ac30b 5055 MSIPACKAGE *package = param;
d3bec325
JH
5056 LPWSTR driver, driver_path, ptr;
5057 WCHAR outpath[MAX_PATH];
5058 MSIFILE *driver_file, *setup_file;
5059 LPCWSTR desc;
5060 DWORD len, usage;
5061 UINT r = ERROR_SUCCESS;
5062
5063 static const WCHAR driver_fmt[] = {
5064 'D','r','i','v','e','r','=','%','s',0};
5065 static const WCHAR setup_fmt[] = {
5066 'S','e','t','u','p','=','%','s',0};
5067 static const WCHAR usage_fmt[] = {
5068 'F','i','l','e','U','s','a','g','e','=','1',0};
5069
5070 desc = MSI_RecordGetString(rec, 3);
5071
5072 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5073 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5074
5075 if (!driver_file || !setup_file)
5076 {
5077 ERR("ODBC Driver entry not found!\n");
5078 return ERROR_FUNCTION_FAILED;
5079 }
5080
5081 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
5082 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
5083 lstrlenW(usage_fmt) + 1;
5084 driver = msi_alloc(len * sizeof(WCHAR));
5085 if (!driver)
5086 return ERROR_OUTOFMEMORY;
5087
5088 ptr = driver;
5089 lstrcpyW(ptr, desc);
5090 ptr += lstrlenW(ptr) + 1;
5091
5092 sprintfW(ptr, driver_fmt, driver_file->FileName);
5093 ptr += lstrlenW(ptr) + 1;
5094
5095 sprintfW(ptr, setup_fmt, setup_file->FileName);
5096 ptr += lstrlenW(ptr) + 1;
5097
5098 lstrcpyW(ptr, usage_fmt);
5099 ptr += lstrlenW(ptr) + 1;
5100 *ptr = '\0';
5101
5102 driver_path = strdupW(driver_file->TargetPath);
5103 ptr = strrchrW(driver_path, '\\');
5104 if (ptr) *ptr = '\0';
5105
5106 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5107 NULL, ODBC_INSTALL_COMPLETE, &usage))
5108 {
5109 ERR("Failed to install SQL driver!\n");
5110 r = ERROR_FUNCTION_FAILED;
5111 }
5112
5113 msi_free(driver);
5114 msi_free(driver_path);
5115
5116 return r;
5117}
5118
33c025b7
HL
5119static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5120{
5f3ac30b 5121 MSIPACKAGE *package = param;
33c025b7
HL
5122 LPWSTR translator, translator_path, ptr;
5123 WCHAR outpath[MAX_PATH];
5124 MSIFILE *translator_file, *setup_file;
5125 LPCWSTR desc;
5126 DWORD len, usage;
5127 UINT r = ERROR_SUCCESS;
5128
5129 static const WCHAR translator_fmt[] = {
5130 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5131 static const WCHAR setup_fmt[] = {
5132 'S','e','t','u','p','=','%','s',0};
5133
5134 desc = MSI_RecordGetString(rec, 3);
5135
5136 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5137 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5138
5139 if (!translator_file || !setup_file)
5140 {
5141 ERR("ODBC Translator entry not found!\n");
5142 return ERROR_FUNCTION_FAILED;
5143 }
5144
5145 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
5146 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
5147 translator = msi_alloc(len * sizeof(WCHAR));
5148 if (!translator)
5149 return ERROR_OUTOFMEMORY;
5150
5151 ptr = translator;
5152 lstrcpyW(ptr, desc);
5153 ptr += lstrlenW(ptr) + 1;
5154
5155 sprintfW(ptr, translator_fmt, translator_file->FileName);
5156 ptr += lstrlenW(ptr) + 1;
5157
5158 sprintfW(ptr, setup_fmt, setup_file->FileName);
5159 ptr += lstrlenW(ptr) + 1;
5160 *ptr = '\0';
5161
5162 translator_path = strdupW(translator_file->TargetPath);
5163 ptr = strrchrW(translator_path, '\\');
5164 if (ptr) *ptr = '\0';
5165
5166 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5167 NULL, ODBC_INSTALL_COMPLETE, &usage))
5168 {
5169 ERR("Failed to install SQL translator!\n");
5170 r = ERROR_FUNCTION_FAILED;
5171 }
5172
5173 msi_free(translator);
5174 msi_free(translator_path);
5175
5176 return r;
5177}
5178
1d19c2b7
HL
5179static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5180{
5181 LPWSTR attrs;
5182 LPCWSTR desc, driver;
5183 WORD request = ODBC_ADD_SYS_DSN;
5184 INT registration;
5185 DWORD len;
5186 UINT r = ERROR_SUCCESS;
5187
5188 static const WCHAR attrs_fmt[] = {
5189 'D','S','N','=','%','s',0 };
5190
5191 desc = MSI_RecordGetString(rec, 3);
5192 driver = MSI_RecordGetString(rec, 4);
5193 registration = MSI_RecordGetInteger(rec, 5);
5194
5195 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5196 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5197
5198 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
5199 attrs = msi_alloc(len * sizeof(WCHAR));
5200 if (!attrs)
5201 return ERROR_OUTOFMEMORY;
5202
5203 sprintfW(attrs, attrs_fmt, desc);
5204 attrs[len - 1] = '\0';
5205
5206 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5207 {
5208 ERR("Failed to install SQL data source!\n");
5209 r = ERROR_FUNCTION_FAILED;
5210 }
5211
5212 msi_free(attrs);
5213
5214 return r;
5215}
5216
d3bec325
JH
5217static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5218{
5219 UINT rc;
5220 MSIQUERY *view;
5221
33c025b7 5222 static const WCHAR driver_query[] = {
d3bec325
JH
5223 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5224 'O','D','B','C','D','r','i','v','e','r',0 };
5225
33c025b7
HL
5226 static const WCHAR translator_query[] = {
5227 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5228 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5229
1d19c2b7
HL
5230 static const WCHAR source_query[] = {
5231 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5232 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5233
33c025b7 5234 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
d3bec325
JH
5235 if (rc != ERROR_SUCCESS)
5236 return ERROR_SUCCESS;
5237
5238 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5239 msiobj_release(&view->hdr);
5240
33c025b7
HL
5241 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5242 if (rc != ERROR_SUCCESS)
5243 return ERROR_SUCCESS;
5244
5245 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5246 msiobj_release(&view->hdr);
5247
1d19c2b7
HL
5248 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5249 if (rc != ERROR_SUCCESS)
5250 return ERROR_SUCCESS;
5251
5252 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5253 msiobj_release(&view->hdr);
5254
d3bec325
JH
5255 return rc;
5256}
5257
5b8641a5
JH
5258#define ENV_ACT_SETALWAYS 0x1
5259#define ENV_ACT_SETABSENT 0x2
5260#define ENV_ACT_REMOVE 0x4
881f5925 5261#define ENV_ACT_REMOVEMATCH 0x8
5b8641a5
JH
5262
5263#define ENV_MOD_MACHINE 0x20000000
5264#define ENV_MOD_APPEND 0x40000000
5265#define ENV_MOD_PREFIX 0x80000000
881f5925
JH
5266#define ENV_MOD_MASK 0xC0000000
5267
5268#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5269
d5b620ea 5270static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
881f5925
JH
5271{
5272 LPCWSTR cptr = *name;
d5b620ea 5273 LPCWSTR ptr = *value;
881f5925
JH
5274
5275 static const WCHAR prefix[] = {'[','~',']',0};
d5b620ea 5276 static const int prefix_len = 3;
881f5925
JH
5277
5278 *flags = 0;
6076485f 5279 while (*cptr)
881f5925 5280 {
6076485f 5281 if (*cptr == '=')
881f5925 5282 *flags |= ENV_ACT_SETALWAYS;
6076485f 5283 else if (*cptr == '+')
881f5925 5284 *flags |= ENV_ACT_SETABSENT;
6076485f 5285 else if (*cptr == '-')
881f5925 5286 *flags |= ENV_ACT_REMOVE;
6076485f 5287 else if (*cptr == '!')
881f5925 5288 *flags |= ENV_ACT_REMOVEMATCH;
6076485f 5289 else if (*cptr == '*')
881f5925 5290 *flags |= ENV_MOD_MACHINE;
6076485f 5291 else
881f5925 5292 break;
881f5925
JH
5293
5294 cptr++;
5295 (*name)++;
5296 }
5297
5298 if (!*cptr)
5299 {
5300 ERR("Missing environment variable\n");
5301 return ERROR_FUNCTION_FAILED;
5302 }
5303
d5b620ea 5304 if (!strncmpW(ptr, prefix, prefix_len))
881f5925 5305 {
d5b620ea 5306 *flags |= ENV_MOD_APPEND;
881f5925
JH
5307 *value += lstrlenW(prefix);
5308 }
d5b620ea 5309 else if (lstrlenW(*value) >= prefix_len)
881f5925 5310 {
d5b620ea 5311 ptr += lstrlenW(ptr) - prefix_len;
881f5925
JH
5312 if (!lstrcmpW(ptr, prefix))
5313 {
d5b620ea
MZ
5314 *flags |= ENV_MOD_PREFIX;
5315 /* the "[~]" will be removed by deformat_string */;
881f5925
JH
5316 }
5317 }
5318
659768e2 5319 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
881f5925
JH
5320 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5321 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5322 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5323 {
5324 ERR("Invalid flags: %08x\n", *flags);
5325 return ERROR_FUNCTION_FAILED;
5326 }
5327
659768e2
HL
5328 if (!*flags)
5329 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5330
881f5925
JH
5331 return ERROR_SUCCESS;
5332}
5b8641a5
JH
5333
5334static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5335{
881f5925 5336 MSIPACKAGE *package = param;
68975938 5337 LPCWSTR name, value;
881f5925 5338 LPWSTR data = NULL, newval = NULL;
d5b620ea 5339 LPWSTR deformatted = NULL, ptr;
5b8641a5
JH
5340 DWORD flags, type, size;
5341 LONG res;
9d71238a
JH
5342 HKEY env = NULL, root;
5343 LPCWSTR environment;
5b8641a5 5344
9d71238a
JH
5345 static const WCHAR user_env[] =
5346 {'E','n','v','i','r','o','n','m','e','n','t',0};
5347 static const WCHAR machine_env[] =
5b8641a5
JH
5348 {'S','y','s','t','e','m','\\',
5349 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5350 'C','o','n','t','r','o','l','\\',
5351 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5352 'E','n','v','i','r','o','n','m','e','n','t',0};
5353 static const WCHAR semicolon[] = {';',0};
5354
881f5925
JH
5355 name = MSI_RecordGetString(rec, 2);
5356 value = MSI_RecordGetString(rec, 3);
881f5925 5357
659768e2
HL
5358 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
5359
d5b620ea 5360 res = env_set_flags(&name, &value, &flags);
881f5925
JH
5361 if (res != ERROR_SUCCESS)
5362 goto done;
5b8641a5 5363
d5b620ea
MZ
5364 deformat_string(package, value, &deformatted);
5365 if (!deformatted)
5366 {
5367 res = ERROR_OUTOFMEMORY;
5368 goto done;
5369 }
5370
881f5925 5371 value = deformatted;
5b8641a5
JH
5372
5373 if (flags & ENV_MOD_MACHINE)
9d71238a
JH
5374 {
5375 environment = machine_env;
5b8641a5 5376 root = HKEY_LOCAL_MACHINE;
9d71238a
JH
5377 }
5378 else
5379 {
5380 environment = user_env;
5381 root = HKEY_CURRENT_USER;
5382 }
5b8641a5 5383
9d71238a
JH
5384 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5385 KEY_ALL_ACCESS, NULL, &env, NULL);
5b8641a5 5386 if (res != ERROR_SUCCESS)
881f5925 5387 goto done;
5b8641a5
JH
5388
5389 if (flags & ENV_ACT_REMOVE)
881f5925 5390 FIXME("Not removing environment variable on uninstall!\n");
5b8641a5
JH
5391
5392 size = 0;
881f5925
JH
5393 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5394 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
31c461ea 5395 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
881f5925 5396 goto done;
5b8641a5
JH
5397
5398 if (res != ERROR_FILE_NOT_FOUND)
5399 {
5400 if (flags & ENV_ACT_SETABSENT)
5401 {
5402 res = ERROR_SUCCESS;
5403 goto done;
5404 }
5405
881f5925
JH
5406 data = msi_alloc(size);
5407 if (!data)
5b8641a5 5408 {
881f5925
JH
5409 RegCloseKey(env);
5410 return ERROR_OUTOFMEMORY;
5b8641a5
JH
5411 }
5412
881f5925
JH
5413 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5414 if (res != ERROR_SUCCESS)
5415 goto done;
5416
5417 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5b8641a5 5418 {
881f5925
JH
5419 res = RegDeleteKeyW(env, name);
5420 goto done;
5b8641a5
JH
5421 }
5422
881f5925
JH
5423 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5424 newval = msi_alloc(size);
5425 ptr = newval;
5426 if (!newval)
5427 {
5428 res = ERROR_OUTOFMEMORY;
5b8641a5 5429 goto done;
881f5925 5430 }
5b8641a5 5431
881f5925
JH
5432 if (!(flags & ENV_MOD_MASK))
5433 lstrcpyW(newval, value);
5434 else
5b8641a5 5435 {
881f5925
JH
5436 if (flags & ENV_MOD_PREFIX)
5437 {
5438 lstrcpyW(newval, value);
5439 lstrcatW(newval, semicolon);
5440 ptr = newval + lstrlenW(value) + 1;
5441 }
5442
5443 lstrcpyW(ptr, data);
5444
5445 if (flags & ENV_MOD_APPEND)
5446 {
5447 lstrcatW(newval, semicolon);
5448 lstrcatW(newval, value);
5449 }
5b8641a5
JH
5450 }
5451 }
5452 else
5453 {
5454 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
881f5925
JH
5455 newval = msi_alloc(size);
5456 if (!newval)
5b8641a5
JH
5457 {
5458 res = ERROR_OUTOFMEMORY;
5459 goto done;
5460 }
5461
881f5925 5462 lstrcpyW(newval, value);
5b8641a5
JH
5463 }
5464
881f5925
JH
5465 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5466 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
5b8641a5
JH
5467
5468done:
0e4ccb82 5469 if (env) RegCloseKey(env);
881f5925
JH
5470 msi_free(deformatted);
5471 msi_free(data);
5472 msi_free(newval);
5b8641a5
JH
5473 return res;
5474}
5475
5476static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5477{
5478 UINT rc;
5479 MSIQUERY * view;
5480 static const WCHAR ExecSeqQuery[] =
5481 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5482 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5483 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5484 if (rc != ERROR_SUCCESS)
5485 return ERROR_SUCCESS;
5486
5487 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5488 msiobj_release(&view->hdr);
5489
5490 return rc;
5491}
5492
c3df74e2
JH
5493#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5494
5495typedef struct
5496{
5497 struct list entry;
5498 LPWSTR sourcename;
5499 LPWSTR destname;
5500 LPWSTR source;
5501 LPWSTR dest;
5502} FILE_LIST;
5503
5504static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5505{
5506 BOOL ret;
5507
5508 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5509 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5510 {
5511 WARN("Source or dest is directory, not moving\n");
5512 return FALSE;
5513 }
5514
5515 if (options == msidbMoveFileOptionsMove)
5516 {
5517 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5518 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5519 if (!ret)
5520 {
5521 WARN("MoveFile failed: %d\n", GetLastError());
5522 return FALSE;
5523 }
5524 }
5525 else
5526 {
5527 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5528 ret = CopyFileW(source, dest, FALSE);
5529 if (!ret)
5530 {
5531 WARN("CopyFile failed: %d\n", GetLastError());
5532 return FALSE;
5533 }
5534 }
5535
5536 return TRUE;
5537}
5538
5539static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5540{
5541 LPWSTR path, ptr;
5542 DWORD dirlen, pathlen;
5543
5544 ptr = strrchrW(wildcard, '\\');
5545 dirlen = ptr - wildcard + 1;
5546
5547 pathlen = dirlen + lstrlenW(filename) + 1;
5548 path = msi_alloc(pathlen * sizeof(WCHAR));
5549
5550 lstrcpynW(path, wildcard, dirlen + 1);
5551 lstrcatW(path, filename);
5552
5553 return path;
5554}
5555
5556static void free_file_entry(FILE_LIST *file)
5557{
5558 msi_free(file->source);
5559 msi_free(file->dest);
5560 msi_free(file);
5561}
5562
5563static void free_list(FILE_LIST *list)
5564{
5565 while (!list_empty(&list->entry))
5566 {
5567 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5568
5569 list_remove(&file->entry);
5570 free_file_entry(file);
5571 }
5572}
5573
5574static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5575{
5576 FILE_LIST *new, *file;
5577 LPWSTR ptr, filename;
5578 DWORD size;
5579
5580 new = msi_alloc_zero(sizeof(FILE_LIST));
5581 if (!new)
5582 return FALSE;
5583
5584 new->source = strdupW(source);
5585 ptr = strrchrW(dest, '\\') + 1;
5586 filename = strrchrW(new->source, '\\') + 1;
5587
5588 new->sourcename = filename;
5589
5590 if (*ptr)
5591 new->destname = ptr;
5592 else
5593 new->destname = new->sourcename;
5594
5595 size = (ptr - dest) + lstrlenW(filename) + 1;
5596 new->dest = msi_alloc(size * sizeof(WCHAR));
5597 if (!new->dest)
5598 {
5599 free_file_entry(new);
5600 return FALSE;
5601 }
5602
5603 lstrcpynW(new->dest, dest, ptr - dest + 1);
5604 lstrcatW(new->dest, filename);
5605
5606 if (list_empty(&files->entry))
5607 {
5608 list_add_head(&files->entry, &new->entry);
5609 return TRUE;
5610 }
5611
5612 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5613 {
5614 if (lstrcmpW(source, file->source) < 0)
5615 {
5616 list_add_before(&file->entry, &new->entry);
5617 return TRUE;
5618 }
5619 }
5620
5621 list_add_after(&file->entry, &new->entry);
5622 return TRUE;
5623}
5624
4439e0b5 5625static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
c3df74e2
JH
5626{
5627 WIN32_FIND_DATAW wfd;
5628 HANDLE hfile;
5629 LPWSTR path;
5630 BOOL res;
5631 FILE_LIST files, *file;
5632 DWORD size;
5633
5634 hfile = FindFirstFileW(source, &wfd);
5635 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5636
5637 list_init(&files.entry);
5638
5639 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5640 {
5641 if (is_dot_dir(wfd.cFileName)) continue;
5642
5643 path = wildcard_to_file(source, wfd.cFileName);
5644 if (!path)
5645 {
fa8476e7
JH
5646 res = FALSE;
5647 goto done;
c3df74e2
JH
5648 }
5649
5650 add_wildcard(&files, path, dest);
5651 msi_free(path);
5652 }
5653
a7d02a1f
JH
5654 /* no files match the wildcard */
5655 if (list_empty(&files.entry))
5656 goto done;
5657
c3df74e2
JH
5658 /* only the first wildcard match gets renamed to dest */
5659 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5660 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5661 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5662 if (!file->dest)
5663 {
fa8476e7
JH
5664 res = FALSE;
5665 goto done;
c3df74e2
JH
5666 }
5667
5668 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5669
5670 while (!list_empty(&files.entry))
5671 {
5672 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5673
5f3ac30b 5674 msi_move_file(file->source, file->dest, options);
c3df74e2
JH
5675
5676 list_remove(&file->entry);
5677 free_file_entry(file);
5678 }
5679
fa8476e7
JH
5680 res = TRUE;
5681
5682done:
5683 free_list(&files);
5684 FindClose(hfile);
5685 return res;
c3df74e2
JH
5686}
5687
5688static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5689{
5690 MSIPACKAGE *package = param;
5691 MSICOMPONENT *comp;
ef1b0cac
RS
5692 LPCWSTR sourcename;
5693 LPWSTR destname = NULL;
c3df74e2
JH
5694 LPWSTR sourcedir = NULL, destdir = NULL;
5695 LPWSTR source = NULL, dest = NULL;
5696 int options;
5697 DWORD size;
5698 BOOL ret, wildcards;
5699
5700 static const WCHAR backslash[] = {'\\',0};
5701
5702 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5703 if (!comp || !comp->Enabled ||
5704 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5705 {
5706 TRACE("Component not set for install, not moving file\n");
5707 return ERROR_SUCCESS;
5708 }
5709
5710 sourcename = MSI_RecordGetString(rec, 3);
c3df74e2
JH
5711 options = MSI_RecordGetInteger(rec, 7);
5712
5713 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5714 if (!sourcedir)
5715 goto done;
5716
5717 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5718 if (!destdir)
5719 goto done;
5720
5721 if (!sourcename)
5722 {
5723 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5724 goto done;
5725
5726 source = strdupW(sourcedir);
5727 if (!source)
5728 goto done;
5729 }
5730 else
5731 {
5732 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5733 source = msi_alloc(size * sizeof(WCHAR));
5734 if (!source)
5735 goto done;
5736
5737 lstrcpyW(source, sourcedir);
5738 if (source[lstrlenW(source) - 1] != '\\')
5739 lstrcatW(source, backslash);
5740 lstrcatW(source, sourcename);
5741 }
5742
5743 wildcards = strchrW(source, '*') || strchrW(source, '?');
5744
ef1b0cac 5745 if (MSI_RecordIsNull(rec, 4))
c3df74e2 5746 {
ef1b0cac
RS
5747 if (!wildcards)
5748 {
5749 destname = strdupW(sourcename);
5750 if (!destname)
5751 goto done;
5752 }
5753 }
5754 else
5755 {
5756 destname = strdupW(MSI_RecordGetString(rec, 4));
5757 if (destname)
5758 reduce_to_longfilename(destname);
c3df74e2
JH
5759 }
5760
5761 size = 0;
5762 if (destname)
5763 size = lstrlenW(destname);
5764
5765 size += lstrlenW(destdir) + 2;
5766 dest = msi_alloc(size * sizeof(WCHAR));
5767 if (!dest)
5768 goto done;
5769
5770 lstrcpyW(dest, destdir);
5771 if (dest[lstrlenW(dest) - 1] != '\\')
5772 lstrcatW(dest, backslash);
5773
5774 if (destname)
5775 lstrcatW(dest, destname);
5776
5777 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5778 {
5779 ret = CreateDirectoryW(destdir, NULL);
5780 if (!ret)
5781 {
5782 WARN("CreateDirectory failed: %d\n", GetLastError());
5783 return ERROR_SUCCESS;
5784 }
5785 }
5786
5787 if (!wildcards)
5788 msi_move_file(source, dest, options);
5789 else
5790 move_files_wildcard(source, dest, options);
5791
5792done:
5793 msi_free(sourcedir);
5794 msi_free(destdir);
ef1b0cac 5795 msi_free(destname);
c3df74e2
JH
5796 msi_free(source);
5797 msi_free(dest);
5798
5799 return ERROR_SUCCESS;
5800}
5801
5802static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5803{
5804 UINT rc;
5805 MSIQUERY *view;
5806
5807 static const WCHAR ExecSeqQuery[] =
5808 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5809 '`','M','o','v','e','F','i','l','e','`',0};
5810
5811 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5812 if (rc != ERROR_SUCCESS)
5813 return ERROR_SUCCESS;
5814
5815 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5816 msiobj_release(&view->hdr);
5817
5818 return rc;
5819}
5820
74239fcd
JH
5821typedef struct tagMSIASSEMBLY
5822{
5823 struct list entry;
5824 MSICOMPONENT *component;
5825 MSIFEATURE *feature;
5826 MSIFILE *file;
5827 LPWSTR manifest;
5828 LPWSTR application;
5829 DWORD attributes;
5830 BOOL installed;
5831} MSIASSEMBLY;
5832
bfe07d1d
JH
5833static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5834 DWORD dwReserved);
5835static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5836 LPVOID pvReserved, HMODULE *phModDll);
5837
5838static BOOL init_functionpointers(void)
5839{
5840 HRESULT hr;
5841 HMODULE hfusion;
5842 HMODULE hmscoree;
5843
5844 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5845
5846 hmscoree = LoadLibraryA("mscoree.dll");
5847 if (!hmscoree)
5848 {
5849 WARN("mscoree.dll not available\n");
5850 return FALSE;
5851 }
5852
5853 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5854 if (!pLoadLibraryShim)
5855 {
5856 WARN("LoadLibraryShim not available\n");
5857 FreeLibrary(hmscoree);
5858 return FALSE;
5859 }
5860
5861 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5862 if (FAILED(hr))
5863 {
5864 WARN("fusion.dll not available\n");
5865 FreeLibrary(hmscoree);
5866 return FALSE;
5867 }
5868
5869 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5870
5871 FreeLibrary(hmscoree);
5872 return TRUE;
5873}
5874
d596ae29
JH
5875static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
5876 LPWSTR path)
bfe07d1d
JH
5877{
5878 IAssemblyCache *cache;
5879 HRESULT hr;
5880 UINT r = ERROR_FUNCTION_FAILED;
5881
74239fcd
JH
5882 TRACE("installing assembly: %s\n", debugstr_w(path));
5883
5884 if (assembly->feature)
d596ae29 5885 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
74239fcd
JH
5886
5887 if (assembly->manifest)
5888 FIXME("Manifest unhandled\n");
5889
5890 if (assembly->application)
5891 {
5892 FIXME("Assembly should be privately installed\n");
5893 return ERROR_SUCCESS;
5894 }
5895
5896 if (assembly->attributes == msidbAssemblyAttributesWin32)
5897 {
5898 FIXME("Win32 assemblies not handled\n");
5899 return ERROR_SUCCESS;
5900 }
5901
bfe07d1d
JH
5902 hr = pCreateAssemblyCache(&cache, 0);
5903 if (FAILED(hr))
5904 goto done;
5905
5906 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5907 if (FAILED(hr))
5908 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5909
5910 r = ERROR_SUCCESS;
5911
5912done:
5913 IAssemblyCache_Release(cache);
5914 return r;
5915}
5916
74239fcd 5917typedef struct tagASSEMBLY_LIST
bfe07d1d 5918{
74239fcd 5919 MSIPACKAGE *package;
019f4af1 5920 IAssemblyCache *cache;
74239fcd
JH
5921 struct list *assemblies;
5922} ASSEMBLY_LIST;
bfe07d1d 5923
019f4af1
JH
5924typedef struct tagASSEMBLY_NAME
5925{
5926 LPWSTR name;
5927 LPWSTR version;
5928 LPWSTR culture;
5929 LPWSTR pubkeytoken;
5930} ASSEMBLY_NAME;
5931
5932static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
5933{
5f3ac30b 5934 ASSEMBLY_NAME *asmname = param;
019f4af1
JH
5935 LPCWSTR name = MSI_RecordGetString(rec, 2);
5936 LPWSTR val = msi_dup_record_field(rec, 3);
5937
5938 static const WCHAR Name[] = {'N','a','m','e',0};
5939 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
5940 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
5941 static const WCHAR PublicKeyToken[] = {
5942 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
5943
43094e4a 5944 if (!strcmpiW(name, Name))
019f4af1 5945 asmname->name = val;
43094e4a 5946 else if (!strcmpiW(name, Version))
019f4af1 5947 asmname->version = val;
43094e4a 5948 else if (!strcmpiW(name, Culture))
019f4af1 5949 asmname->culture = val;
43094e4a 5950 else if (!strcmpiW(name, PublicKeyToken))
019f4af1
JH
5951 asmname->pubkeytoken = val;
5952 else
5953 msi_free(val);
5954
5955 return ERROR_SUCCESS;
5956}
5957
5958static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
5959{
5960 if (!*str)
5961 {
5962 *size = lstrlenW(append) + 1;
5963 *str = msi_alloc((*size) * sizeof(WCHAR));
5964 lstrcpyW(*str, append);
5965 return;
5966 }
5967
5968 (*size) += lstrlenW(append);
5969 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
5970 lstrcatW(*str, append);
5971}
5972
5973static BOOL check_assembly_installed(MSIDATABASE *db, IAssemblyCache *cache,
5974 MSICOMPONENT *comp)
5975{
5976 ASSEMBLY_INFO asminfo;
5977 ASSEMBLY_NAME name;
5978 MSIQUERY *view;
5979 LPWSTR disp;
5980 DWORD size;
5981 BOOL found;
5982 UINT r;
5983
5984 static const WCHAR separator[] = {',',' ',0};
5985 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
5986 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
5987 static const WCHAR PublicKeyToken[] = {
5988 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
5989 static const WCHAR query[] = {
5990 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5991 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
5992 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
5993 '=','\'','%','s','\'',0};
5994
5995 disp = NULL;
5996 found = FALSE;
5997 ZeroMemory(&name, sizeof(ASSEMBLY_NAME));
5998 ZeroMemory(&asminfo, sizeof(ASSEMBLY_INFO));
5999
6000 r = MSI_OpenQuery(db, &view, query, comp->Component);
6001 if (r != ERROR_SUCCESS)
6002 return ERROR_SUCCESS;
6003
6004 MSI_IterateRecords(view, NULL, parse_assembly_name, &name);
6005 msiobj_release(&view->hdr);
6006
6007 if (!name.name)
6008 {
6009 ERR("No assembly name specified!\n");
6010 goto done;
6011 }
6012
6013 append_str(&disp, &size, name.name);
6014
6015 if (name.version)
6016 {
6017 append_str(&disp, &size, separator);
6018 append_str(&disp, &size, Version);
6019 append_str(&disp, &size, name.version);
6020 }
6021
6022 if (name.culture)
6023 {
6024 append_str(&disp, &size, separator);
6025 append_str(&disp, &size, Culture);
6026 append_str(&disp, &size, name.culture);
6027 }
6028
6029 if (name.pubkeytoken)
6030 {
6031 append_str(&disp, &size, separator);
6032 append_str(&disp, &size, PublicKeyToken);
6033 append_str(&disp, &size, name.pubkeytoken);
6034 }
6035
6036 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
6037 IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE,
6038 disp, &asminfo);
6039 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
6040
6041done:
019f4af1
JH
6042 msi_free(disp);
6043 msi_free(name.name);
6044 msi_free(name.version);
6045 msi_free(name.culture);
6046 msi_free(name.pubkeytoken);
6047
6048 return found;
6049}
6050
74239fcd
JH
6051static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6052{
5f3ac30b 6053 ASSEMBLY_LIST *list = param;
74239fcd
JH
6054 MSIASSEMBLY *assembly;
6055
6056 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6057 if (!assembly)
6058 return ERROR_OUTOFMEMORY;
6059
6060 assembly->component = get_loaded_component(list->package, MSI_RecordGetString(rec, 1));
6061
6062 if (!assembly->component || !assembly->component->Enabled ||
6063 !(assembly->component->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
bfe07d1d 6064 {
92ed390b 6065 TRACE("Component not set for install, not publishing assembly\n");
74239fcd 6066 msi_free(assembly);
bfe07d1d
JH
6067 return ERROR_SUCCESS;
6068 }
6069
74239fcd
JH
6070 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6071 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
bfe07d1d 6072
74239fcd 6073 if (!assembly->file)
bfe07d1d 6074 {
74239fcd
JH
6075 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
6076 return ERROR_FUNCTION_FAILED;
bfe07d1d
JH
6077 }
6078
74239fcd
JH
6079 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6080 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6081 assembly->attributes = MSI_RecordGetInteger(rec, 5);
9c6e6efa
HL
6082
6083 if (assembly->application)
6084 {
6085 WCHAR version[24];
6086 DWORD size = sizeof(version)/sizeof(WCHAR);
6087
6088 /* FIXME: we should probably check the manifest file here */
6089
6090 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
7d837b9f 6091 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
9c6e6efa
HL
6092 {
6093 assembly->installed = TRUE;
6094 }
6095 }
6096 else
6097 assembly->installed = check_assembly_installed(list->package->db,
6098 list->cache,
6099 assembly->component);
74239fcd
JH
6100
6101 list_add_head(list->assemblies, &assembly->entry);
74239fcd
JH
6102 return ERROR_SUCCESS;
6103}
6104
6105static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6106{
019f4af1 6107 IAssemblyCache *cache = NULL;
74239fcd 6108 ASSEMBLY_LIST list;
019f4af1
JH
6109 MSIQUERY *view;
6110 HRESULT hr;
74239fcd
JH
6111 UINT r;
6112
6113 static const WCHAR query[] =
6114 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6115 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6116
6117 r = MSI_DatabaseOpenViewW(package->db, query, &view);
6118 if (r != ERROR_SUCCESS)
bfe07d1d 6119 return ERROR_SUCCESS;
bfe07d1d 6120
019f4af1
JH
6121 hr = pCreateAssemblyCache(&cache, 0);
6122 if (FAILED(hr))
6123 return ERROR_FUNCTION_FAILED;
6124
74239fcd 6125 list.package = package;
019f4af1 6126 list.cache = cache;
74239fcd
JH
6127 list.assemblies = assemblies;
6128
6129 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6130 msiobj_release(&view->hdr);
6131
019f4af1
JH
6132 IAssemblyCache_Release(cache);
6133
74239fcd
JH
6134 return r;
6135}
6136
6137static void free_assemblies(struct list *assemblies)
6138{
6139 struct list *item, *cursor;
6140
6141 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
70cd6bfb 6142 {
74239fcd
JH
6143 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6144
6145 list_remove(&assembly->entry);
6146 msi_free(assembly->application);
6147 msi_free(assembly->manifest);
6148 msi_free(assembly);
70cd6bfb 6149 }
74239fcd 6150}
bfe07d1d 6151
74239fcd
JH
6152static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6153{
6154 MSIASSEMBLY *assembly;
9460ae35 6155
74239fcd 6156 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
bfe07d1d 6157 {
74239fcd 6158 if (!lstrcmpW(assembly->file->File, file))
9460ae35 6159 {
74239fcd
JH
6160 *out = assembly;
6161 return TRUE;
9460ae35 6162 }
bfe07d1d 6163 }
74239fcd
JH
6164
6165 return FALSE;
6166}
6167
6168static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6169 LPWSTR *path, DWORD *attrs, PVOID user)
6170{
6171 MSIASSEMBLY *assembly;
6172 WCHAR temppath[MAX_PATH];
5f3ac30b 6173 struct list *assemblies = user;
74239fcd
JH
6174 UINT r;
6175
6176 if (!find_assembly(assemblies, file, &assembly))
6177 return FALSE;
6178
6179 GetTempPathW(MAX_PATH, temppath);
6180 PathAddBackslashW(temppath);
6181 lstrcatW(temppath, assembly->file->FileName);
6182
6183 if (action == MSICABEXTRACT_BEGINEXTRACT)
9460ae35 6184 {
74239fcd
JH
6185 if (assembly->installed)
6186 return FALSE;
bfe07d1d 6187
74239fcd
JH
6188 *path = strdupW(temppath);
6189 *attrs = assembly->file->Attributes;
9460ae35 6190 }
74239fcd
JH
6191 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6192 {
6193 assembly->installed = TRUE;
bfe07d1d 6194
d596ae29 6195 r = install_assembly(package, assembly, temppath);
74239fcd
JH
6196 if (r != ERROR_SUCCESS)
6197 ERR("Failed to install assembly\n");
6198 }
bfe07d1d 6199
74239fcd 6200 return TRUE;
bfe07d1d
JH
6201}
6202
6203static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6204{
74239fcd
JH
6205 UINT r;
6206 struct list assemblies = LIST_INIT(assemblies);
6207 MSIASSEMBLY *assembly;
6208 MSIMEDIAINFO *mi;
bfe07d1d 6209
019f4af1
JH
6210 if (!init_functionpointers() || !pCreateAssemblyCache)
6211 return ERROR_FUNCTION_FAILED;
6212
74239fcd
JH
6213 r = load_assemblies(package, &assemblies);
6214 if (r != ERROR_SUCCESS)
6215 goto done;
bfe07d1d 6216
74239fcd
JH
6217 if (list_empty(&assemblies))
6218 goto done;
bfe07d1d 6219
74239fcd
JH
6220 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6221 if (!mi)
6222 {
6223 r = ERROR_OUTOFMEMORY;
6224 goto done;
6225 }
bfe07d1d 6226
74239fcd
JH
6227 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6228 {
6229 if (assembly->installed && !mi->is_continuous)
6230 continue;
6231
6232 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6233 (assembly->file->IsCompressed && !mi->is_extracted))
6234 {
6235 MSICABDATA data;
6236
6237 r = ready_media(package, assembly->file, mi);
6238 if (r != ERROR_SUCCESS)
6239 {
6240 ERR("Failed to ready media\n");
6241 break;
6242 }
6243
6244 data.mi = mi;
6245 data.package = package;
6246 data.cb = installassembly_cb;
6247 data.user = &assemblies;
6248
6249 if (assembly->file->IsCompressed &&
6250 !msi_cabextract(package, mi, &data))
6251 {
6252 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6253 r = ERROR_FUNCTION_FAILED;
6254 break;
6255 }
6256 }
6257
6258 if (!assembly->file->IsCompressed)
6259 {
d15fddf6 6260 LPWSTR source = resolve_file_source(package, assembly->file);
74239fcd 6261
d15fddf6 6262 r = install_assembly(package, assembly, source);
74239fcd
JH
6263 if (r != ERROR_SUCCESS)
6264 ERR("Failed to install assembly\n");
d15fddf6
JH
6265
6266 msi_free(source);
74239fcd
JH
6267 }
6268
6269 /* FIXME: write Installer assembly reg values */
6270 }
6271
6272done:
6273 free_assemblies(&assemblies);
6274 return r;
bfe07d1d
JH
6275}
6276
2586a095
MM
6277static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6278 LPCSTR action, LPCWSTR table )
202166c3 6279{
2586a095
MM
6280 static const WCHAR query[] = {
6281 'S','E','L','E','C','T',' ','*',' ',
6282 'F','R','O','M',' ','`','%','s','`',0 };
202166c3
MM
6283 MSIQUERY *view = NULL;
6284 DWORD count = 0;
2586a095 6285 UINT r;
202166c3 6286
2586a095
MM
6287 r = MSI_OpenQuery( package->db, &view, query, table );
6288 if (r == ERROR_SUCCESS)
202166c3 6289 {
2586a095 6290 r = MSI_IterateRecords(view, &count, NULL, package);
202166c3
MM
6291 msiobj_release(&view->hdr);
6292 }
6293
2586a095 6294 if (count)
f1d4646a 6295 FIXME("%s -> %u ignored %s table values\n",
2586a095
MM
6296 action, count, debugstr_w(table));
6297
202166c3
MM
6298 return ERROR_SUCCESS;
6299}
8e22e7d7 6300
55942702
MM
6301static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6302{
6303 TRACE("%p\n", package);
6304 return ERROR_SUCCESS;
6305}
6306
2586a095 6307static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
8e22e7d7 6308{
2586a095
MM
6309 static const WCHAR table[] =
6310 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
6311 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
6312}
8e22e7d7 6313
2586a095 6314static UINT ACTION_PatchFiles( MSIPACKAGE *package )
567f0314 6315{
2586a095
MM
6316 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6317 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6318}
567f0314 6319
2586a095
MM
6320static UINT ACTION_BindImage( MSIPACKAGE *package )
6321{
6322 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6323 return msi_unimplemented_action_stub( package, "BindImage", table );
567f0314 6324}
94fbe09c 6325
2586a095 6326static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
94fbe09c 6327{
2586a095
MM
6328 static const WCHAR table[] = {
6329 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
6330 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6331}
94fbe09c 6332
2586a095
MM
6333static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6334{
6335 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6336 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
94fbe09c 6337}
b9a3a7a1 6338
2586a095 6339static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
b9a3a7a1 6340{
2586a095
MM
6341 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
6342 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
6343}
b9a3a7a1 6344
2586a095
MM
6345static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6346{
6347 static const WCHAR table[] = {
6348 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
6349 return msi_unimplemented_action_stub( package, "DeleteServices", table );
b9a3a7a1 6350}
ee3ac7a8
SS
6351static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6352{
6353 static const WCHAR table[] = {
6354 'P','r','o','d','u','c','t','I','D',0 };
6355 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
6356}
3b955150 6357
3b955150
MM
6358static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6359{
6360 static const WCHAR table[] = {
6361 'E','n','v','i','r','o','n','m','e','n','t',0 };
6362 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
6363}
6364
3b955150
MM
6365static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6366{
6367 static const WCHAR table[] = {
6368 'M','s','i','A','s','s','e','m','b','l','y',0 };
6369 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6370}
6371
6372static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
6373{
6374 static const WCHAR table[] = { 'F','o','n','t',0 };
6375 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
6376}
6377
f24a9e2a
MM
6378static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6379{
6380 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6381 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6382}
6383
88603669
MM
6384static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6385{
6386 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6387 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6388}
6389
6390static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6391{
6392 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6393 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6394}
6395
987c2c85
JH
6396static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6397{
6398 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6399 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6400}
6401
6402static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
6403{
6404 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
6405 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
6406}
6407
6408static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6409{
6410 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6411 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6412}
6413
6414static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
6415{
6416 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
6417 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
6418}
6419
6420static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6421{
6422 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
6423 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
6424}
6425
6426static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
6427{
6428 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
6429 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
6430}
6431
6432static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
6433{
6434 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
6435 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
6436}
6437
6438static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
6439{
6440 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
6441 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
6442}
6443
987c2c85
JH
6444static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6445{
6446 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6447 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6448}
6449
6450static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6451{
6452 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6453 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6454}
6455
6456static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6457{
6458 static const WCHAR table[] = { 'M','I','M','E',0 };
6459 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6460}
6461
6462static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6463{
6464 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6465 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6466}
6467
6468static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
6469{
6470 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
6471 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
6472}
6473
1cdf5cdd 6474static const struct _actions StandardActions[] = {
55942702 6475 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
3b955150
MM
6476 { szAppSearch, ACTION_AppSearch },
6477 { szBindImage, ACTION_BindImage },
987c2c85 6478 { szCCPSearch, ACTION_CCPSearch },
3b955150
MM
6479 { szCostFinalize, ACTION_CostFinalize },
6480 { szCostInitialize, ACTION_CostInitialize },
6481 { szCreateFolders, ACTION_CreateFolders },
6482 { szCreateShortcuts, ACTION_CreateShortcuts },
6483 { szDeleteServices, ACTION_DeleteServices },
987c2c85 6484 { szDisableRollback, NULL },
3b955150
MM
6485 { szDuplicateFiles, ACTION_DuplicateFiles },
6486 { szExecuteAction, ACTION_ExecuteAction },
6487 { szFileCost, ACTION_FileCost },
6488 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6489 { szForceReboot, ACTION_ForceReboot },
987c2c85 6490 { szInstallAdminPackage, NULL },
3b955150
MM
6491 { szInstallExecute, ACTION_InstallExecute },
6492 { szInstallExecuteAgain, ACTION_InstallExecute },
6493 { szInstallFiles, ACTION_InstallFiles},
6494 { szInstallFinalize, ACTION_InstallFinalize },
6495 { szInstallInitialize, ACTION_InstallInitialize },
987c2c85 6496 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
3b955150
MM
6497 { szInstallValidate, ACTION_InstallValidate },
6498 { szIsolateComponents, ACTION_IsolateComponents },
6499 { szLaunchConditions, ACTION_LaunchConditions },
6500 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6501 { szMoveFiles, ACTION_MoveFiles },
6502 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6503 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
d3bec325 6504 { szInstallODBC, ACTION_InstallODBC },
3b955150
MM
6505 { szInstallServices, ACTION_InstallServices },
6506 { szPatchFiles, ACTION_PatchFiles },
6507 { szProcessComponents, ACTION_ProcessComponents },
6508 { szPublishComponents, ACTION_PublishComponents },
6509 { szPublishFeatures, ACTION_PublishFeatures },
6510 { szPublishProduct, ACTION_PublishProduct },
6511 { szRegisterClassInfo, ACTION_RegisterClassInfo },
88603669 6512 { szRegisterComPlus, ACTION_RegisterComPlus},
3b955150
MM
6513 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6514 { szRegisterFonts, ACTION_RegisterFonts },
6515 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6516 { szRegisterProduct, ACTION_RegisterProduct },
6517 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6518 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
987c2c85
JH
6519 { szRegisterUser, ACTION_RegisterUser },
6520 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
3b955150 6521 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
987c2c85
JH
6522 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6523 { szRemoveFiles, ACTION_RemoveFiles },
6524 { szRemoveFolders, ACTION_RemoveFolders },
3b955150 6525 { szRemoveIniValues, ACTION_RemoveIniValues },
987c2c85
JH
6526 { szRemoveODBC, ACTION_RemoveODBC },
6527 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6528 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6529 { szResolveSource, ACTION_ResolveSource },
6530 { szRMCCPSearch, ACTION_RMCCPSearch },
6531 { szScheduleReboot, NULL },
3b955150
MM
6532 { szSelfRegModules, ACTION_SelfRegModules },
6533 { szSelfUnregModules, ACTION_SelfUnregModules },
987c2c85 6534 { szSetODBCFolders, NULL },
3b955150
MM
6535 { szStartServices, ACTION_StartServices },
6536 { szStopServices, ACTION_StopServices },
987c2c85
JH
6537 { szUnpublishComponents, ACTION_UnpublishComponents },
6538 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6539 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6540 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6541 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
3b955150 6542 { szUnregisterFonts, ACTION_UnregisterFonts },
987c2c85
JH
6543 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6544 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6545 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6546 { szValidateProductID, ACTION_ValidateProductID },
3b955150
MM
6547 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6548 { szWriteIniValues, ACTION_WriteIniValues },
987c2c85
JH
6549 { szWriteRegistryValues, ACTION_WriteRegistryValues },
6550 { NULL, NULL },
3b955150 6551};
9e85ec3b
AT
6552
6553static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6554 UINT* rc, BOOL force )
6555{
6556 BOOL ret = FALSE;
6557 BOOL run = force;
6558 int i;
6559
6560 if (!run && !package->script->CurrentlyScripting)
6561 run = TRUE;
6562
6563 if (!run)
6564 {
6565 if (strcmpW(action,szInstallFinalize) == 0 ||
6566 strcmpW(action,szInstallExecute) == 0 ||
6567 strcmpW(action,szInstallExecuteAgain) == 0)
6568 run = TRUE;
6569 }
6570
6571 i = 0;
6572 while (StandardActions[i].action != NULL)
6573 {
6574 if (strcmpW(StandardActions[i].action, action)==0)
6575 {
6576 if (!run)
6577 {
6578 ui_actioninfo(package, action, TRUE, 0);
6579 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6580 ui_actioninfo(package, action, FALSE, *rc);
6581 }
6582 else
6583 {
6584 ui_actionstart(package, action);
6585 if (StandardActions[i].handler)
6586 {
6587 *rc = StandardActions[i].handler(package);
6588 }
6589 else
6590 {
6591 FIXME("unhandled standard action %s\n",debugstr_w(action));
6592 *rc = ERROR_SUCCESS;
6593 }
6594 }
6595 ret = TRUE;
6596 break;
6597 }
6598 i++;
6599 }
6600 return ret;
6601}