blob: cf403e19ab10766190260db036ce98654f41b194 [file] [log] [blame]
Aric Stewart401bd3f2004-06-28 20:34:35 +00001/*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
Aric Stewartc6689522005-06-17 20:56:55 +00004 * Copyright 2004,2005 Aric Stewart for CodeWeavers
Aric Stewart401bd3f2004-06-28 20:34:35 +00005 *
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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Aric Stewart401bd3f2004-06-28 20:34:35 +000019 */
20
Aric Stewart401bd3f2004-06-28 20:34:35 +000021#include <stdarg.h>
Aric Stewart401bd3f2004-06-28 20:34:35 +000022
Francois Gouget486d0202004-10-07 03:06:48 +000023#define COBJMACROS
24
Aric Stewart401bd3f2004-06-28 20:34:35 +000025#include "windef.h"
26#include "winbase.h"
27#include "winerror.h"
28#include "winreg.h"
James Hawkins9bc12ad2006-10-19 15:49:54 -070029#include "winsvc.h"
James Hawkinsd3bec322006-11-27 18:20:33 -080030#include "odbcinst.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000031#include "wine/debug.h"
Aric Stewartb6bc6aa2005-02-24 12:47:43 +000032#include "msidefs.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000033#include "msipriv.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000034#include "winuser.h"
35#include "shlobj.h"
James Hawkinsbfe07d12008-04-30 04:22:46 -050036#include "objbase.h"
37#include "mscoree.h"
38#include "fusion.h"
39#include "shlwapi.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000040#include "wine/unicode.h"
Steven Edwards98efef12005-04-11 16:10:33 +000041#include "winver.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000042
Aric Stewartbd1bbc12005-01-03 20:00:13 +000043#define REG_PROGRESS_VALUE 13200
44#define COMPONENT_PROGRESS_VALUE 24000
Aric Stewart401bd3f2004-06-28 20:34:35 +000045
Aric Stewart401bd3f2004-06-28 20:34:35 +000046WINE_DEFAULT_DEBUG_CHANNEL(msi);
47
48/*
Aric Stewart401bd3f2004-06-28 20:34:35 +000049 * consts and values used
50 */
Juan Lang014ad3b2005-03-01 10:41:52 +000051static const WCHAR c_colon[] = {'C',':','\\',0};
Aric Stewartc6689522005-06-17 20:56:55 +000052
Mike McCormack9ba8ba32005-10-30 19:04:26 +000053static const WCHAR szCreateFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000054 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000055static const WCHAR szCostFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000056 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000057static const WCHAR szWriteRegistryValues[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020058 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000059static const WCHAR szCostInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000060 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000061static const WCHAR szFileCost[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000062 {'F','i','l','e','C','o','s','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000063static const WCHAR szInstallInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000064 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000065static const WCHAR szInstallValidate[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000066 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000067static const WCHAR szLaunchConditions[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000068 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000069static const WCHAR szProcessComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000070 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000071static const WCHAR szRegisterTypeLibraries[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020072 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000073static const WCHAR szCreateShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000074 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000075static const WCHAR szPublishProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000076 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000077static const WCHAR szWriteIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000078 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000079static const WCHAR szSelfRegModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000080 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000081static const WCHAR szPublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000082 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000083static const WCHAR szRegisterProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000084 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000085static const WCHAR szInstallExecute[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000086 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000087static const WCHAR szInstallExecuteAgain[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020088 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000089static const WCHAR szInstallFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000090 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000091static const WCHAR szForceReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000092 {'F','o','r','c','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000093static const WCHAR szResolveSource[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000094 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000095static const WCHAR szAllocateRegistrySpace[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020096 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000097static const WCHAR szBindImage[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000098 {'B','i','n','d','I','m','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000099static const WCHAR szDeleteServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000101static const WCHAR szDisableRollback[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000103static const WCHAR szExecuteAction[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000105static const WCHAR szInstallAdminPackage[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000107static const WCHAR szInstallSFPCatalogFile[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000109static const WCHAR szIsolateComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200111static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000113static const WCHAR szMsiPublishAssemblies[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000115static const WCHAR szMsiUnpublishAssemblies[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000117static const WCHAR szInstallODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000118 {'I','n','s','t','a','l','l','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000119static const WCHAR szInstallServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200121static const WCHAR szPatchFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000122 {'P','a','t','c','h','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000123static const WCHAR szPublishComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000125static const WCHAR szRegisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000127static const WCHAR szRegisterFonts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000128 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000129static const WCHAR szRegisterUser[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000130 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000131static const WCHAR szRemoveEnvironmentStrings[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200132 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
133static const WCHAR szRemoveExistingProducts[] =
134 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000135static const WCHAR szRemoveFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000136 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000137static const WCHAR szRemoveIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000138 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000139static const WCHAR szRemoveODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000140 {'R','e','m','o','v','e','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000141static const WCHAR szRemoveRegistryValues[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200142 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000143static const WCHAR szRemoveShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000144 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000145static const WCHAR szRMCCPSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000146 {'R','M','C','C','P','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000147static const WCHAR szScheduleReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000148 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000149static const WCHAR szSelfUnregModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000150 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000151static const WCHAR szSetODBCFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000152 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000153static const WCHAR szStartServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000154 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000155static const WCHAR szStopServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000156 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000157static const WCHAR szUnpublishComponents[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200158 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000159static const WCHAR szUnpublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000160 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200161static const WCHAR szUnregisterClassInfo[] =
162 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000163static const WCHAR szUnregisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000164 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200165static const WCHAR szUnregisterExtensionInfo[] =
166 {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000167static const WCHAR szUnregisterFonts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000168 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200169static const WCHAR szUnregisterMIMEInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000170 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200171static const WCHAR szUnregisterProgIdInfo[] =
172 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000173static const WCHAR szUnregisterTypeLibraries[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200174 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000175static const WCHAR szValidateProductID[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000176 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000177static const WCHAR szWriteEnvironmentStrings[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200178 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
Aric Stewart90c57392005-01-31 16:23:12 +0000179
Aric Stewart2703d712005-06-20 15:33:10 +0000180/********************************************************
181 * helper functions
182 ********************************************************/
183
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000184static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
Aric Stewartd2c395a2004-07-06 18:48:15 +0000185{
Aric Stewartd2c395a2004-07-06 18:48:15 +0000186 static const WCHAR Query_t[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000187 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000188 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
189 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
190 ' ','\'','%','s','\'',0};
Robert Shearmand679bc52006-01-23 17:30:31 +0100191 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000192
Mike McCormack0b352c72005-06-02 10:29:57 +0000193 row = MSI_QueryGetRecord( package->db, Query_t, action );
194 if (!row)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000195 return;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000196 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
197 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000198}
199
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000200static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
Aric Stewartd2c395a2004-07-06 18:48:15 +0000201 UINT rc)
202{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000203 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000204 static const WCHAR template_s[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000205 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
206 '%','s', '.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000207 static const WCHAR template_e[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000208 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
209 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
210 '%','i','.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000211 static const WCHAR format[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000212 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000213 WCHAR message[1024];
214 WCHAR timet[0x100];
215
216 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
217 if (start)
218 sprintfW(message,template_s,timet,action);
219 else
220 sprintfW(message,template_e,timet,action,rc);
221
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000222 row = MSI_CreateRecord(1);
223 MSI_RecordSetStringW(row,1,message);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000224
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000225 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
226 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000227}
228
James Hawkinsca71e5a2008-10-30 04:03:07 -0500229UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
230 BOOL preserve_case )
Mike McCormacke3452222005-09-28 15:12:32 +0000231{
232 LPCWSTR ptr,ptr2;
233 BOOL quote;
234 DWORD len;
235 LPWSTR prop = NULL, val = NULL;
236
237 if (!szCommandLine)
238 return ERROR_SUCCESS;
239
240 ptr = szCommandLine;
241
242 while (*ptr)
243 {
244 if (*ptr==' ')
245 {
246 ptr++;
247 continue;
248 }
249
250 TRACE("Looking at %s\n",debugstr_w(ptr));
251
252 ptr2 = strchrW(ptr,'=');
253 if (!ptr2)
254 {
255 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
256 break;
257 }
258
259 quote = FALSE;
260
261 len = ptr2-ptr;
262 prop = msi_alloc((len+1)*sizeof(WCHAR));
263 memcpy(prop,ptr,len*sizeof(WCHAR));
264 prop[len]=0;
James Hawkinsca71e5a2008-10-30 04:03:07 -0500265
266 if (!preserve_case)
267 struprW(prop);
268
Mike McCormacke3452222005-09-28 15:12:32 +0000269 ptr2++;
270
271 len = 0;
272 ptr = ptr2;
273 while (*ptr && (quote || (!quote && *ptr!=' ')))
274 {
275 if (*ptr == '"')
276 quote = !quote;
277 ptr++;
278 len++;
279 }
280
281 if (*ptr2=='"')
282 {
283 ptr2++;
284 len -= 2;
285 }
286 val = msi_alloc((len+1)*sizeof(WCHAR));
287 memcpy(val,ptr2,len*sizeof(WCHAR));
288 val[len] = 0;
289
290 if (lstrlenW(prop) > 0)
291 {
292 TRACE("Found commandline property (%s) = (%s)\n",
293 debugstr_w(prop), debugstr_w(val));
294 MSI_SetPropertyW(package,prop,val);
295 }
296 msi_free(val);
297 msi_free(prop);
298 }
299
300 return ERROR_SUCCESS;
301}
302
Mike McCormack965a72a2005-10-26 12:06:21 +0000303
304static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
305{
Andrew Talbot2e372c02006-09-17 08:52:49 +0100306 LPCWSTR pc;
Mike McCormack965a72a2005-10-26 12:06:21 +0000307 LPWSTR p, *ret = NULL;
308 UINT count = 0;
309
310 if (!str)
311 return ret;
312
313 /* count the number of substrings */
Andrew Talbot2e372c02006-09-17 08:52:49 +0100314 for ( pc = str, count = 0; pc; count++ )
Mike McCormack965a72a2005-10-26 12:06:21 +0000315 {
Andrew Talbot2e372c02006-09-17 08:52:49 +0100316 pc = strchrW( pc, sep );
317 if (pc)
318 pc++;
Mike McCormack965a72a2005-10-26 12:06:21 +0000319 }
320
321 /* allocate space for an array of substring pointers and the substrings */
322 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
323 (lstrlenW(str)+1) * sizeof(WCHAR) );
324 if (!ret)
325 return ret;
326
327 /* copy the string and set the pointers */
328 p = (LPWSTR) &ret[count+1];
329 lstrcpyW( p, str );
330 for( count = 0; (ret[count] = p); count++ )
331 {
332 p = strchrW( p, sep );
333 if (p)
334 *p++ = 0;
335 }
336
337 return ret;
338}
339
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900340static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
341{
Hans Leidekker86af8762009-03-24 10:26:42 +0100342 static const WCHAR szSystemLanguageID[] =
343 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
344
345 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
346 UINT ret = ERROR_FUNCTION_FAILED;
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900347
348 prod_code = msi_dup_property( package, szProductCode );
349 patch_product = msi_get_suminfo_product( patch );
350
351 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
352
353 if ( strstrW( patch_product, prod_code ) )
Hans Leidekker86af8762009-03-24 10:26:42 +0100354 {
Hans Leidekker86af8762009-03-24 10:26:42 +0100355 MSISUMMARYINFO *si;
356 const WCHAR *p;
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900357
Hans Leidekker86af8762009-03-24 10:26:42 +0100358 si = MSI_GetSummaryInformationW( patch, 0 );
359 if (!si)
360 {
361 ERR("no summary information!\n");
362 goto end;
363 }
364
365 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
366 if (!template)
367 {
368 ERR("no template property!\n");
369 msiobj_release( &si->hdr );
370 goto end;
371 }
372
373 if (!template[0])
374 {
375 ret = ERROR_SUCCESS;
376 msiobj_release( &si->hdr );
377 goto end;
378 }
379
380 langid = msi_dup_property( package, szSystemLanguageID );
381 if (!langid)
382 {
383 msiobj_release( &si->hdr );
384 goto end;
385 }
386
387 p = strchrW( template, ';' );
Hans Leidekker843382f2009-10-15 12:46:27 +0200388 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
Hans Leidekker86af8762009-03-24 10:26:42 +0100389 {
390 TRACE("applicable transform\n");
391 ret = ERROR_SUCCESS;
392 }
393
394 /* FIXME: check platform */
395
396 msiobj_release( &si->hdr );
397 }
398
399end:
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900400 msi_free( patch_product );
401 msi_free( prod_code );
Hans Leidekker86af8762009-03-24 10:26:42 +0100402 msi_free( template );
403 msi_free( langid );
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900404
405 return ret;
406}
407
Mike McCormack965a72a2005-10-26 12:06:21 +0000408static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
409 MSIDATABASE *patch_db, LPCWSTR name )
410{
411 UINT ret = ERROR_FUNCTION_FAILED;
412 IStorage *stg = NULL;
413 HRESULT r;
414
415 TRACE("%p %s\n", package, debugstr_w(name) );
416
417 if (*name++ != ':')
418 {
419 ERR("expected a colon in %s\n", debugstr_w(name));
420 return ERROR_FUNCTION_FAILED;
421 }
422
423 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
424 if (SUCCEEDED(r))
425 {
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900426 ret = msi_check_transform_applicable( package, stg );
427 if (ret == ERROR_SUCCESS)
428 msi_table_apply_transform( package->db, stg );
429 else
430 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
Mike McCormack965a72a2005-10-26 12:06:21 +0000431 IStorage_Release( stg );
Mike McCormack965a72a2005-10-26 12:06:21 +0000432 }
433 else
434 ERR("failed to open substorage %s\n", debugstr_w(name));
435
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900436 return ERROR_SUCCESS;
Mike McCormack965a72a2005-10-26 12:06:21 +0000437}
438
Hans Leidekker05e9a1f2009-09-02 11:44:17 +0200439UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
Mike McCormack965a72a2005-10-26 12:06:21 +0000440{
James Hawkins261e1172007-06-15 14:12:13 -0700441 LPWSTR guid_list, *guids, product_code;
Mike McCormack965a72a2005-10-26 12:06:21 +0000442 UINT i, ret = ERROR_FUNCTION_FAILED;
443
Hans Leidekker843382f2009-10-15 12:46:27 +0200444 product_code = msi_dup_property( package, szProductCode );
James Hawkins261e1172007-06-15 14:12:13 -0700445 if (!product_code)
Mike McCormack965a72a2005-10-26 12:06:21 +0000446 {
James Hawkins261e1172007-06-15 14:12:13 -0700447 /* FIXME: the property ProductCode should be written into the DB somewhere */
448 ERR("no product code to check\n");
Mike McCormack965a72a2005-10-26 12:06:21 +0000449 return ERROR_SUCCESS;
450 }
451
452 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
453 guids = msi_split_string( guid_list, ';' );
454 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
455 {
James Hawkins261e1172007-06-15 14:12:13 -0700456 if (!lstrcmpW( guids[i], product_code ))
Mike McCormack965a72a2005-10-26 12:06:21 +0000457 ret = ERROR_SUCCESS;
458 }
459 msi_free( guids );
460 msi_free( guid_list );
James Hawkins261e1172007-06-15 14:12:13 -0700461 msi_free( product_code );
Mike McCormack965a72a2005-10-26 12:06:21 +0000462
463 return ret;
464}
465
James Hawkinsc059ceb2008-12-14 21:07:28 -0600466static UINT msi_set_media_source_prop(MSIPACKAGE *package)
467{
468 MSIQUERY *view;
469 MSIRECORD *rec = NULL;
470 LPWSTR patch;
471 LPCWSTR prop;
472 UINT r;
473
James Hawkinsc059ceb2008-12-14 21:07:28 -0600474 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
475 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
476 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
477 '`','S','o','u','r','c','e','`',' ','I','S',' ',
478 'N','O','T',' ','N','U','L','L',0};
479
480 r = MSI_DatabaseOpenViewW(package->db, query, &view);
481 if (r != ERROR_SUCCESS)
482 return r;
483
484 r = MSI_ViewExecute(view, 0);
485 if (r != ERROR_SUCCESS)
486 goto done;
487
488 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
489 {
490 prop = MSI_RecordGetString(rec, 1);
491 patch = msi_dup_property(package, szPatch);
492 MSI_SetPropertyW(package, prop, patch);
493 msi_free(patch);
494 }
495
496done:
497 if (rec) msiobj_release(&rec->hdr);
498 msiobj_release(&view->hdr);
499
500 return r;
501}
502
Mike McCormack965a72a2005-10-26 12:06:21 +0000503static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
504{
505 MSISUMMARYINFO *si;
506 LPWSTR str, *substorage;
507 UINT i, r = ERROR_SUCCESS;
508
Mike McCormack7f98f1d2006-10-24 01:11:30 +0900509 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
Mike McCormack965a72a2005-10-26 12:06:21 +0000510 if (!si)
511 return ERROR_FUNCTION_FAILED;
512
James Hawkins01eb9302008-12-14 21:07:23 -0600513 if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
514 {
515 TRACE("Patch not applicable\n");
516 return ERROR_SUCCESS;
517 }
518
519 package->patch = msi_alloc(sizeof(MSIPATCHINFO));
520 if (!package->patch)
521 return ERROR_OUTOFMEMORY;
522
523 package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
524 if (!package->patch->patchcode)
525 return ERROR_OUTOFMEMORY;
Mike McCormack965a72a2005-10-26 12:06:21 +0000526
527 /* enumerate the substorage */
528 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
James Hawkins01eb9302008-12-14 21:07:23 -0600529 package->patch->transforms = str;
530
Mike McCormack965a72a2005-10-26 12:06:21 +0000531 substorage = msi_split_string( str, ';' );
532 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
533 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
James Hawkins01eb9302008-12-14 21:07:23 -0600534
Mike McCormack965a72a2005-10-26 12:06:21 +0000535 msi_free( substorage );
Mike McCormack965a72a2005-10-26 12:06:21 +0000536 msiobj_release( &si->hdr );
537
James Hawkinsc059ceb2008-12-14 21:07:28 -0600538 msi_set_media_source_prop(package);
539
Mike McCormack965a72a2005-10-26 12:06:21 +0000540 return r;
541}
542
543static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
544{
545 MSIDATABASE *patch_db = NULL;
546 UINT r;
547
548 TRACE("%p %s\n", package, debugstr_w( file ) );
549
550 /* FIXME:
551 * We probably want to make sure we only open a patch collection here.
552 * Patch collections (.msp) and databases (.msi) have different GUIDs
553 * but currently MSI_OpenDatabaseW will accept both.
554 */
555 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
556 if ( r != ERROR_SUCCESS )
557 {
558 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
559 return r;
560 }
561
562 msi_parse_patch_summary( package, patch_db );
Mike McCormack9a4ba8c2006-11-01 15:09:23 +0900563
564 /*
565 * There might be a CAB file in the patch package,
566 * so append it to the list of storage to search for streams.
567 */
568 append_storage_to_db( package->db, patch_db->storage );
569
Mike McCormack965a72a2005-10-26 12:06:21 +0000570 msiobj_release( &patch_db->hdr );
571
572 return ERROR_SUCCESS;
573}
574
575/* get the PATCH property, and apply all the patches it specifies */
576static UINT msi_apply_patches( MSIPACKAGE *package )
577{
Mike McCormack965a72a2005-10-26 12:06:21 +0000578 LPWSTR patch_list, *patches;
579 UINT i, r = ERROR_SUCCESS;
580
581 patch_list = msi_dup_property( package, szPatch );
582
583 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
584
585 patches = msi_split_string( patch_list, ';' );
586 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
587 r = msi_apply_patch_package( package, patches[i] );
588
589 msi_free( patches );
590 msi_free( patch_list );
591
592 return r;
593}
594
Mike McCormacke534e772006-01-04 14:51:25 +0100595static UINT msi_apply_transforms( MSIPACKAGE *package )
596{
597 static const WCHAR szTransforms[] = {
598 'T','R','A','N','S','F','O','R','M','S',0 };
599 LPWSTR xform_list, *xforms;
600 UINT i, r = ERROR_SUCCESS;
601
602 xform_list = msi_dup_property( package, szTransforms );
603 xforms = msi_split_string( xform_list, ';' );
604
605 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
606 {
607 if (xforms[i][0] == ':')
James Hawkins776a7d72008-03-10 23:03:50 -0500608 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
Mike McCormacke534e772006-01-04 14:51:25 +0100609 else
610 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
611 }
612
613 msi_free( xforms );
614 msi_free( xform_list );
615
616 return r;
617}
618
James Hawkins4439e0b2008-02-29 23:29:43 -0600619static BOOL ui_sequence_exists( MSIPACKAGE *package )
James Hawkins6da80412007-04-15 03:10:58 -0500620{
621 MSIQUERY *view;
622 UINT rc;
623
624 static const WCHAR ExecSeqQuery [] =
625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
626 '`','I','n','s','t','a','l','l',
627 'U','I','S','e','q','u','e','n','c','e','`',
628 ' ','W','H','E','R','E',' ',
629 '`','S','e','q','u','e','n','c','e','`',' ',
630 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
631 '`','S','e','q','u','e','n','c','e','`',0};
632
633 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
634 if (rc == ERROR_SUCCESS)
635 {
636 msiobj_release(&view->hdr);
637 return TRUE;
638 }
639
640 return FALSE;
641}
642
James Hawkinsc777d302008-01-05 13:45:13 -0700643static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
644{
James Hawkins062070b2008-01-05 13:46:39 -0700645 LPWSTR p, db;
James Hawkinsc777d302008-01-05 13:45:13 -0700646 LPWSTR source, check;
647 DWORD len;
648
James Hawkinsc37849a2008-01-05 13:50:59 -0700649 static const WCHAR szOriginalDatabase[] =
650 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
651
James Hawkins062070b2008-01-05 13:46:39 -0700652 db = msi_dup_property( package, szOriginalDatabase );
653 if (!db)
654 return ERROR_OUTOFMEMORY;
James Hawkinsc777d302008-01-05 13:45:13 -0700655
James Hawkins062070b2008-01-05 13:46:39 -0700656 p = strrchrW( db, '\\' );
657 if (!p)
658 {
James Hawkins18648762008-01-05 13:47:14 -0700659 p = strrchrW( db, '/' );
660 if (!p)
661 {
662 msi_free(db);
663 return ERROR_SUCCESS;
664 }
James Hawkins062070b2008-01-05 13:46:39 -0700665 }
666
667 len = p - db + 2;
James Hawkinsc777d302008-01-05 13:45:13 -0700668 source = msi_alloc( len * sizeof(WCHAR) );
James Hawkins062070b2008-01-05 13:46:39 -0700669 lstrcpynW( source, db, len );
James Hawkinsc777d302008-01-05 13:45:13 -0700670
671 check = msi_dup_property( package, cszSourceDir );
672 if (!check || replace)
673 MSI_SetPropertyW( package, cszSourceDir, source );
674
675 msi_free( check );
676
677 check = msi_dup_property( package, cszSOURCEDIR );
678 if (!check || replace)
679 MSI_SetPropertyW( package, cszSOURCEDIR, source );
680
681 msi_free( check );
682 msi_free( source );
James Hawkins062070b2008-01-05 13:46:39 -0700683 msi_free( db );
James Hawkinsc777d302008-01-05 13:45:13 -0700684
685 return ERROR_SUCCESS;
686}
687
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200688static BOOL needs_ui_sequence(MSIPACKAGE *package)
689{
690 INT level = msi_get_property_int(package, szUILevel, 0);
691 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
692}
693
James Hawkins5f112622008-06-18 00:50:28 -0500694static UINT msi_set_context(MSIPACKAGE *package)
695{
696 WCHAR val[10];
697 DWORD sz = 10;
698 DWORD num;
699 UINT r;
700
James Hawkins5f112622008-06-18 00:50:28 -0500701 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
702
703 r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
704 if (r == ERROR_SUCCESS)
705 {
706 num = atolW(val);
707 if (num == 1 || num == 2)
708 package->Context = MSIINSTALLCONTEXT_MACHINE;
709 }
710
James Hawkins5f112622008-06-18 00:50:28 -0500711 return ERROR_SUCCESS;
712}
713
Aric Stewart2703d712005-06-20 15:33:10 +0000714static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
715{
Aric Stewart2703d712005-06-20 15:33:10 +0000716 UINT rc;
717 LPCWSTR cond, action;
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200718 MSIPACKAGE *package = param;
Aric Stewart2703d712005-06-20 15:33:10 +0000719
720 action = MSI_RecordGetString(row,1);
721 if (!action)
722 {
723 ERR("Error is retrieving action name\n");
Mike McCormack9375fd92006-10-27 17:29:02 +0900724 return ERROR_FUNCTION_FAILED;
Aric Stewart2703d712005-06-20 15:33:10 +0000725 }
726
727 /* check conditions */
728 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900729
730 /* this is a hack to skip errors in the condition code */
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200731 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
Aric Stewart2703d712005-06-20 15:33:10 +0000732 {
Mike McCormack9375fd92006-10-27 17:29:02 +0900733 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
734 return ERROR_SUCCESS;
Aric Stewart2703d712005-06-20 15:33:10 +0000735 }
736
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200737 if (needs_ui_sequence(package))
738 rc = ACTION_PerformUIAction(package, action, -1);
Aric Stewart2703d712005-06-20 15:33:10 +0000739 else
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200740 rc = ACTION_PerformAction(package, action, -1, FALSE);
Aric Stewart2703d712005-06-20 15:33:10 +0000741
Mike McCormack4f634a32005-07-06 15:44:51 +0000742 msi_dialog_check_messages( NULL );
743
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200744 if (package->CurrentInstallState != ERROR_SUCCESS)
745 rc = package->CurrentInstallState;
Mike McCormack4f634a32005-07-06 15:44:51 +0000746
Aric Stewart2703d712005-06-20 15:33:10 +0000747 if (rc == ERROR_FUNCTION_NOT_CALLED)
748 rc = ERROR_SUCCESS;
749
750 if (rc != ERROR_SUCCESS)
Mike McCormack558abec2005-10-27 12:39:28 +0000751 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
Aric Stewart2703d712005-06-20 15:33:10 +0000752
753 return rc;
754}
755
Mike McCormackd34b1c22005-09-21 10:55:23 +0000756UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
757{
758 MSIQUERY * view;
759 UINT r;
760 static const WCHAR query[] =
761 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
762 '`','%','s','`',
763 ' ','W','H','E','R','E',' ',
764 '`','S','e','q','u','e','n','c','e','`',' ',
765 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
766 '`','S','e','q','u','e','n','c','e','`',0};
Mike McCormackd34b1c22005-09-21 10:55:23 +0000767
768 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
769
770 r = MSI_OpenQuery( package->db, &view, query, szTable );
771 if (r == ERROR_SUCCESS)
772 {
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200773 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
Mike McCormackd34b1c22005-09-21 10:55:23 +0000774 msiobj_release(&view->hdr);
775 }
776
777 return r;
778}
779
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000780static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000781{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000782 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000783 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000784 static const WCHAR ExecSeqQuery[] =
785 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000786 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
787 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
788 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000789 'O','R','D','E','R',' ', 'B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000790 '`','S','e','q','u','e','n','c','e','`',0 };
Aric Stewart8e233e92005-03-01 11:45:19 +0000791 static const WCHAR IVQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +0000792 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
793 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
794 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
795 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
796 ' ','\'', 'I','n','s','t','a','l','l',
797 'V','a','l','i','d','a','t','e','\'', 0};
Mike McCormack9db0e072004-12-22 15:05:07 +0000798 INT seq = 0;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000799
Aric Stewart9cd707d2005-05-27 19:24:22 +0000800 if (package->script->ExecuteSequenceRun)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000801 {
802 TRACE("Execute Sequence already Run\n");
803 return ERROR_SUCCESS;
804 }
805
Aric Stewart9cd707d2005-05-27 19:24:22 +0000806 package->script->ExecuteSequenceRun = TRUE;
Aric Stewart2703d712005-06-20 15:33:10 +0000807
Mike McCormack9db0e072004-12-22 15:05:07 +0000808 /* get the sequence number */
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000809 if (UIran)
810 {
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200811 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
Mike McCormack0b352c72005-06-02 10:29:57 +0000812 if( !row )
813 return ERROR_FUNCTION_FAILED;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000814 seq = MSI_RecordGetInteger(row,1);
815 msiobj_release(&row->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000816 }
Mike McCormack9db0e072004-12-22 15:05:07 +0000817
Mike McCormack0c238852005-01-21 16:19:11 +0000818 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000819 if (rc == ERROR_SUCCESS)
820 {
Aric Stewart2703d712005-06-20 15:33:10 +0000821 TRACE("Running the actions\n");
Aric Stewart401bd3f2004-06-28 20:34:35 +0000822
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200823 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000824 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000825 }
826
Aric Stewart401bd3f2004-06-28 20:34:35 +0000827 return rc;
828}
829
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000830static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000831{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000832 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000833 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000834 static const WCHAR ExecSeqQuery [] =
835 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000836 '`','I','n','s','t','a','l','l',
837 'U','I','S','e','q','u','e','n','c','e','`',
838 ' ','W','H','E','R','E',' ',
839 '`','S','e','q','u','e','n','c','e','`',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000840 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000841 '`','S','e','q','u','e','n','c','e','`',0};
Aric Stewart2703d712005-06-20 15:33:10 +0000842
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000843 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000844 if (rc == ERROR_SUCCESS)
845 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000846 TRACE("Running the actions\n");
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000847
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200848 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000849 msiobj_release(&view->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000850 }
851
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000852 return rc;
853}
854
Aric Stewart401bd3f2004-06-28 20:34:35 +0000855/********************************************************
856 * ACTION helper functions and functions that perform the actions
857 *******************************************************/
Mike McCormackf9acfe62005-06-07 20:29:51 +0000858static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100859 UINT* rc, UINT script, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +0000860{
861 BOOL ret=FALSE;
862 UINT arc;
863
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100864 arc = ACTION_CustomAction(package, action, script, force);
Aric Stewart3f318602005-02-01 18:46:26 +0000865
866 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
867 {
868 *rc = arc;
869 ret = TRUE;
870 }
871 return ret;
872}
Aric Stewart401bd3f2004-06-28 20:34:35 +0000873
Aric Stewart2274ff12005-06-21 20:03:46 +0000874/*
875 * Actual Action Handlers
876 */
877
878static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
879{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +0100880 MSIPACKAGE *package = param;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +0100881 LPCWSTR dir, component;
Aric Stewart2274ff12005-06-21 20:03:46 +0000882 LPWSTR full_path;
883 MSIRECORD *uirow;
884 MSIFOLDER *folder;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +0100885 MSICOMPONENT *comp;
886
887 component = MSI_RecordGetString(row, 2);
888 comp = get_loaded_component(package, component);
889 if (!comp)
890 return ERROR_SUCCESS;
891
892 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
893 {
894 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
895 comp->Action = comp->Installed;
896 return ERROR_SUCCESS;
897 }
898 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart2274ff12005-06-21 20:03:46 +0000899
900 dir = MSI_RecordGetString(row,1);
901 if (!dir)
902 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000903 ERR("Unable to get folder id\n");
Aric Stewart2274ff12005-06-21 20:03:46 +0000904 return ERROR_SUCCESS;
905 }
906
Hans Leidekkera70d86d2010-03-05 12:24:18 +0100907 uirow = MSI_CreateRecord(1);
908 MSI_RecordSetStringW(uirow, 1, dir);
909 ui_actiondata(package, szCreateFolders, uirow);
910 msiobj_release(&uirow->hdr);
911
James Hawkins8cedb212007-03-29 02:38:57 -0500912 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
Aric Stewart2274ff12005-06-21 20:03:46 +0000913 if (!full_path)
914 {
915 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
916 return ERROR_SUCCESS;
917 }
918
919 TRACE("Folder is %s\n",debugstr_w(full_path));
920
Aric Stewart2274ff12005-06-21 20:03:46 +0000921 if (folder->State == 0)
922 create_full_pathW(full_path);
923
924 folder->State = 3;
925
Mike McCormackee034ba2005-09-20 11:59:14 +0000926 msi_free(full_path);
Aric Stewart2274ff12005-06-21 20:03:46 +0000927 return ERROR_SUCCESS;
928}
929
Mike McCormack03b4dbb2005-10-28 09:39:29 +0000930/* FIXME: probably should merge this with the above function */
931static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
932{
933 UINT rc = ERROR_SUCCESS;
934 MSIFOLDER *folder;
935 LPWSTR install_path;
936
James Hawkins8cedb212007-03-29 02:38:57 -0500937 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
Mike McCormack03b4dbb2005-10-28 09:39:29 +0000938 if (!install_path)
939 return ERROR_FUNCTION_FAILED;
940
941 /* create the path */
942 if (folder->State == 0)
943 {
944 create_full_pathW(install_path);
945 folder->State = 2;
946 }
947 msi_free(install_path);
948
949 return rc;
950}
Aric Stewart2274ff12005-06-21 20:03:46 +0000951
Mike McCormack9c845852005-10-29 11:29:17 +0000952UINT msi_create_component_directories( MSIPACKAGE *package )
953{
954 MSICOMPONENT *comp;
955
956 /* create all the folders required by the components are going to install */
957 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
958 {
Hans Leidekker598c5422010-02-16 11:44:47 +0100959 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Mike McCormack9c845852005-10-29 11:29:17 +0000960 continue;
961 msi_create_directory( package, comp->Directory );
962 }
963
964 return ERROR_SUCCESS;
965}
966
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000967static UINT ACTION_CreateFolders(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +0000968{
Aric Stewart8e233e92005-03-01 11:45:19 +0000969 static const WCHAR ExecSeqQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +0000970 {'S','E','L','E','C','T',' ',
971 '`','D','i','r','e','c','t','o','r','y','_','`',
Aric Stewart8e233e92005-03-01 11:45:19 +0000972 ' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000973 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +0000974 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000975 MSIQUERY *view;
Aric Stewart401bd3f2004-06-28 20:34:35 +0000976
Mike McCormack03b4dbb2005-10-28 09:39:29 +0000977 /* create all the empty folders specified in the CreateFolder table */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000978 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
Aric Stewart401bd3f2004-06-28 20:34:35 +0000979 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +0000980 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +0000981
Aric Stewart2274ff12005-06-21 20:03:46 +0000982 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000983 msiobj_release(&view->hdr);
Mike McCormack03b4dbb2005-10-28 09:39:29 +0000984
Aric Stewart401bd3f2004-06-28 20:34:35 +0000985 return rc;
986}
987
Hans Leidekker3864ddf2010-02-05 14:47:55 +0100988static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
989{
990 MSIPACKAGE *package = param;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +0100991 LPCWSTR dir, component;
Hans Leidekker3864ddf2010-02-05 14:47:55 +0100992 LPWSTR full_path;
993 MSIRECORD *uirow;
994 MSIFOLDER *folder;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +0100995 MSICOMPONENT *comp;
996
997 component = MSI_RecordGetString(row, 2);
998 comp = get_loaded_component(package, component);
999 if (!comp)
1000 return ERROR_SUCCESS;
1001
1002 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1003 {
1004 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1005 comp->Action = comp->Installed;
1006 return ERROR_SUCCESS;
1007 }
1008 comp->Action = INSTALLSTATE_ABSENT;
Hans Leidekker3864ddf2010-02-05 14:47:55 +01001009
1010 dir = MSI_RecordGetString( row, 1 );
1011 if (!dir)
1012 {
1013 ERR("Unable to get folder id\n");
1014 return ERROR_SUCCESS;
1015 }
1016
1017 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1018 if (!full_path)
1019 {
1020 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1021 return ERROR_SUCCESS;
1022 }
1023
1024 TRACE("folder is %s\n", debugstr_w(full_path));
1025
1026 uirow = MSI_CreateRecord( 1 );
1027 MSI_RecordSetStringW( uirow, 1, full_path );
1028 ui_actiondata( package, szRemoveFolders, uirow );
1029 msiobj_release( &uirow->hdr );
1030
1031 RemoveDirectoryW( full_path );
1032 folder->State = 0;
1033
1034 msi_free( full_path );
1035 return ERROR_SUCCESS;
1036}
1037
1038static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1039{
1040 static const WCHAR query[] =
1041 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1042 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1043
1044 MSIQUERY *view;
1045 UINT rc;
1046
1047 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1048 if (rc != ERROR_SUCCESS)
1049 return ERROR_SUCCESS;
1050
1051 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1052 msiobj_release( &view->hdr );
1053
1054 return rc;
1055}
1056
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001057static UINT load_component( MSIRECORD *row, LPVOID param )
Aric Stewartbdb29552004-07-04 00:32:48 +00001058{
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001059 MSIPACKAGE *package = param;
Mike McCormack38d67a42005-08-22 09:15:23 +00001060 MSICOMPONENT *comp;
Aric Stewartbdb29552004-07-04 00:32:48 +00001061
Mike McCormackee034ba2005-09-20 11:59:14 +00001062 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
Mike McCormack38d67a42005-08-22 09:15:23 +00001063 if (!comp)
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001064 return ERROR_FUNCTION_FAILED;
1065
1066 list_add_tail( &package->components, &comp->entry );
Mike McCormack38d67a42005-08-22 09:15:23 +00001067
Aric Stewartbdb29552004-07-04 00:32:48 +00001068 /* fill in the data */
Mike McCormack51c66182005-10-27 12:36:12 +00001069 comp->Component = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001070
Mike McCormackefcc1ec2005-09-12 12:07:15 +00001071 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
Aric Stewartbdb29552004-07-04 00:32:48 +00001072
Mike McCormack51c66182005-10-27 12:36:12 +00001073 comp->ComponentId = msi_dup_record_field( row, 2 );
1074 comp->Directory = msi_dup_record_field( row, 3 );
Mike McCormack38d67a42005-08-22 09:15:23 +00001075 comp->Attributes = MSI_RecordGetInteger(row,4);
Mike McCormack51c66182005-10-27 12:36:12 +00001076 comp->Condition = msi_dup_record_field( row, 5 );
1077 comp->KeyPath = msi_dup_record_field( row, 6 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001078
James Hawkinsd893cb72006-09-20 19:55:01 -07001079 comp->Installed = INSTALLSTATE_UNKNOWN;
James Hawkins3bec1622008-08-25 00:07:52 -05001080 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001081
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001082 return ERROR_SUCCESS;
1083}
Aric Stewartbdb29552004-07-04 00:32:48 +00001084
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001085static UINT load_all_components( MSIPACKAGE *package )
1086{
1087 static const WCHAR query[] = {
1088 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1089 '`','C','o','m','p','o','n','e','n','t','`',0 };
1090 MSIQUERY *view;
1091 UINT r;
1092
1093 if (!list_empty(&package->components))
1094 return ERROR_SUCCESS;
1095
1096 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1097 if (r != ERROR_SUCCESS)
1098 return r;
1099
1100 r = MSI_IterateRecords(view, NULL, load_component, package);
1101 msiobj_release(&view->hdr);
1102 return r;
Aric Stewartbdb29552004-07-04 00:32:48 +00001103}
1104
Aric Stewart04598242005-06-23 16:43:24 +00001105typedef struct {
1106 MSIPACKAGE *package;
Mike McCormack1da28582005-08-22 14:09:17 +00001107 MSIFEATURE *feature;
Aric Stewart04598242005-06-23 16:43:24 +00001108} _ilfs;
1109
Mike McCormack38d67a42005-08-22 09:15:23 +00001110static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001111{
1112 ComponentList *cl;
1113
Mike McCormackee034ba2005-09-20 11:59:14 +00001114 cl = msi_alloc( sizeof (*cl) );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001115 if ( !cl )
1116 return ERROR_NOT_ENOUGH_MEMORY;
Mike McCormack38d67a42005-08-22 09:15:23 +00001117 cl->component = comp;
Mike McCormack1da28582005-08-22 14:09:17 +00001118 list_add_tail( &feature->Components, &cl->entry );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001119
1120 return ERROR_SUCCESS;
1121}
1122
James Hawkins545d0e72006-09-20 19:59:19 -07001123static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1124{
1125 FeatureList *fl;
1126
1127 fl = msi_alloc( sizeof(*fl) );
1128 if ( !fl )
1129 return ERROR_NOT_ENOUGH_MEMORY;
1130 fl->feature = child;
1131 list_add_tail( &parent->Children, &fl->entry );
1132
1133 return ERROR_SUCCESS;
1134}
1135
Aric Stewart04598242005-06-23 16:43:24 +00001136static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1137{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001138 _ilfs* ilfs = param;
Aric Stewart04598242005-06-23 16:43:24 +00001139 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00001140 MSICOMPONENT *comp;
Aric Stewart04598242005-06-23 16:43:24 +00001141
1142 component = MSI_RecordGetString(row,1);
1143
1144 /* check to see if the component is already loaded */
Mike McCormack38d67a42005-08-22 09:15:23 +00001145 comp = get_loaded_component( ilfs->package, component );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001146 if (!comp)
Aric Stewart04598242005-06-23 16:43:24 +00001147 {
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001148 ERR("unknown component %s\n", debugstr_w(component));
1149 return ERROR_FUNCTION_FAILED;
Aric Stewart04598242005-06-23 16:43:24 +00001150 }
1151
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001152 add_feature_component( ilfs->feature, comp );
1153 comp->Enabled = TRUE;
Aric Stewart04598242005-06-23 16:43:24 +00001154
1155 return ERROR_SUCCESS;
1156}
1157
James Hawkins545d0e72006-09-20 19:59:19 -07001158static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1159{
1160 MSIFEATURE *feature;
1161
James Hawkinsbfe07d12008-04-30 04:22:46 -05001162 if ( !name )
1163 return NULL;
1164
James Hawkins545d0e72006-09-20 19:59:19 -07001165 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1166 {
1167 if ( !lstrcmpW( feature->Feature, name ) )
1168 return feature;
1169 }
1170
1171 return NULL;
1172}
1173
Aric Stewart04598242005-06-23 16:43:24 +00001174static UINT load_feature(MSIRECORD * row, LPVOID param)
1175{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001176 MSIPACKAGE* package = param;
Mike McCormack1da28582005-08-22 14:09:17 +00001177 MSIFEATURE* feature;
Aric Stewart8e233e92005-03-01 11:45:19 +00001178 static const WCHAR Query1[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001179 {'S','E','L','E','C','T',' ',
1180 '`','C','o','m','p','o','n','e','n','t','_','`',
1181 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1182 'C','o','m','p','o','n','e','n','t','s','`',' ',
1183 'W','H','E','R','E',' ',
1184 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001185 MSIQUERY * view;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001186 UINT rc;
Aric Stewart04598242005-06-23 16:43:24 +00001187 _ilfs ilfs;
1188
Aric Stewartbdb29552004-07-04 00:32:48 +00001189 /* fill in the data */
1190
Mike McCormackee034ba2005-09-20 11:59:14 +00001191 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
Mike McCormack1da28582005-08-22 14:09:17 +00001192 if (!feature)
1193 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartbdb29552004-07-04 00:32:48 +00001194
James Hawkins545d0e72006-09-20 19:59:19 -07001195 list_init( &feature->Children );
Mike McCormack1da28582005-08-22 14:09:17 +00001196 list_init( &feature->Components );
Aric Stewartbdb29552004-07-04 00:32:48 +00001197
Mike McCormack51c66182005-10-27 12:36:12 +00001198 feature->Feature = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001199
Mike McCormack1da28582005-08-22 14:09:17 +00001200 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
Aric Stewartbdb29552004-07-04 00:32:48 +00001201
Mike McCormack51c66182005-10-27 12:36:12 +00001202 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1203 feature->Title = msi_dup_record_field( row, 3 );
1204 feature->Description = msi_dup_record_field( row, 4 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001205
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001206 if (!MSI_RecordIsNull(row,5))
Mike McCormack1da28582005-08-22 14:09:17 +00001207 feature->Display = MSI_RecordGetInteger(row,5);
Aric Stewartbdb29552004-07-04 00:32:48 +00001208
Mike McCormack1da28582005-08-22 14:09:17 +00001209 feature->Level= MSI_RecordGetInteger(row,6);
Mike McCormack51c66182005-10-27 12:36:12 +00001210 feature->Directory = msi_dup_record_field( row, 7 );
Mike McCormack1da28582005-08-22 14:09:17 +00001211 feature->Attributes = MSI_RecordGetInteger(row,8);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001212
James Hawkinsca5c1102006-09-20 19:53:56 -07001213 feature->Installed = INSTALLSTATE_UNKNOWN;
James Hawkinsd596ae22008-08-25 00:07:18 -05001214 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
Mike McCormack1da28582005-08-22 14:09:17 +00001215
1216 list_add_tail( &package->features, &feature->entry );
Aric Stewartbdb29552004-07-04 00:32:48 +00001217
1218 /* load feature components */
1219
Mike McCormack1da28582005-08-22 14:09:17 +00001220 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001221 if (rc != ERROR_SUCCESS)
Aric Stewart04598242005-06-23 16:43:24 +00001222 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001223
Mike McCormack1da28582005-08-22 14:09:17 +00001224 ilfs.package = package;
1225 ilfs.feature = feature;
1226
Aric Stewart04598242005-06-23 16:43:24 +00001227 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001228 msiobj_release(&view->hdr);
Aric Stewart04598242005-06-23 16:43:24 +00001229
1230 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001231}
1232
James Hawkins545d0e72006-09-20 19:59:19 -07001233static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1234{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001235 MSIPACKAGE* package = param;
James Hawkins545d0e72006-09-20 19:59:19 -07001236 MSIFEATURE *parent, *child;
1237
1238 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1239 if (!child)
1240 return ERROR_FUNCTION_FAILED;
1241
1242 if (!child->Feature_Parent)
1243 return ERROR_SUCCESS;
1244
1245 parent = find_feature_by_name( package, child->Feature_Parent );
1246 if (!parent)
1247 return ERROR_FUNCTION_FAILED;
1248
1249 add_feature_child( parent, child );
1250 return ERROR_SUCCESS;
1251}
1252
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001253static UINT load_all_features( MSIPACKAGE *package )
1254{
1255 static const WCHAR query[] = {
1256 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1257 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1258 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1259 MSIQUERY *view;
1260 UINT r;
1261
1262 if (!list_empty(&package->features))
1263 return ERROR_SUCCESS;
1264
1265 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1266 if (r != ERROR_SUCCESS)
1267 return r;
1268
1269 r = MSI_IterateRecords( view, NULL, load_feature, package );
James Hawkins545d0e72006-09-20 19:59:19 -07001270 if (r != ERROR_SUCCESS)
1271 return r;
1272
1273 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001274 msiobj_release( &view->hdr );
James Hawkins545d0e72006-09-20 19:59:19 -07001275
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001276 return r;
1277}
1278
Mike McCormackc1513be2006-03-21 19:40:36 +09001279static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1280{
1281 if (!p)
1282 return p;
1283 p = strchrW(p, ch);
1284 if (!p)
1285 return p;
1286 *p = 0;
1287 return p+1;
1288}
1289
James Hawkins41607222007-11-25 18:01:19 -06001290static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1291{
1292 static const WCHAR query[] = {
1293 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1294 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1295 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1296 MSIQUERY *view = NULL;
James Hawkins1277e1b2007-12-14 15:18:05 -06001297 MSIRECORD *row = NULL;
James Hawkins41607222007-11-25 18:01:19 -06001298 UINT r;
1299
1300 TRACE("%s\n", debugstr_w(file->File));
1301
1302 r = MSI_OpenQuery(package->db, &view, query, file->File);
1303 if (r != ERROR_SUCCESS)
1304 goto done;
1305
1306 r = MSI_ViewExecute(view, NULL);
1307 if (r != ERROR_SUCCESS)
1308 goto done;
1309
1310 r = MSI_ViewFetch(view, &row);
1311 if (r != ERROR_SUCCESS)
1312 goto done;
1313
1314 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1315 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1316 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1317 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1318 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1319
1320done:
1321 if (view) msiobj_release(&view->hdr);
James Hawkins1277e1b2007-12-14 15:18:05 -06001322 if (row) msiobj_release(&row->hdr);
James Hawkins41607222007-11-25 18:01:19 -06001323 return r;
1324}
1325
Aric Stewart04598242005-06-23 16:43:24 +00001326static UINT load_file(MSIRECORD *row, LPVOID param)
Aric Stewartc5a14432005-05-18 17:46:12 +00001327{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001328 MSIPACKAGE* package = param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00001329 LPCWSTR component;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001330 MSIFILE *file;
Aric Stewartc5a14432005-05-18 17:46:12 +00001331
1332 /* fill in the data */
1333
Mike McCormackee034ba2005-09-20 11:59:14 +00001334 file = msi_alloc_zero( sizeof (MSIFILE) );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001335 if (!file)
1336 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartc5a14432005-05-18 17:46:12 +00001337
Mike McCormack51c66182005-10-27 12:36:12 +00001338 file->File = msi_dup_record_field( row, 1 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001339
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001340 component = MSI_RecordGetString( row, 2 );
1341 file->Component = get_loaded_component( package, component );
Aric Stewart09b0aba2005-06-09 20:30:59 +00001342
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001343 if (!file->Component)
James Hawkins9a8d2f32008-08-18 23:00:20 -05001344 {
1345 WARN("Component not found: %s\n", debugstr_w(component));
1346 msi_free(file->File);
1347 msi_free(file);
1348 return ERROR_SUCCESS;
1349 }
Aric Stewartc5a14432005-05-18 17:46:12 +00001350
Mike McCormack51c66182005-10-27 12:36:12 +00001351 file->FileName = msi_dup_record_field( row, 3 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001352 reduce_to_longfilename( file->FileName );
Aric Stewartc5a14432005-05-18 17:46:12 +00001353
Mike McCormack51c66182005-10-27 12:36:12 +00001354 file->ShortName = msi_dup_record_field( row, 3 );
Mike McCormackc1513be2006-03-21 19:40:36 +09001355 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
Aric Stewartc5a14432005-05-18 17:46:12 +00001356
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001357 file->FileSize = MSI_RecordGetInteger( row, 4 );
Mike McCormack51c66182005-10-27 12:36:12 +00001358 file->Version = msi_dup_record_field( row, 5 );
1359 file->Language = msi_dup_record_field( row, 6 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001360 file->Attributes = MSI_RecordGetInteger( row, 7 );
1361 file->Sequence = MSI_RecordGetInteger( row, 8 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001362
Mike McCormackdded8fb2005-11-02 10:56:42 +00001363 file->state = msifs_invalid;
Aric Stewartc5a14432005-05-18 17:46:12 +00001364
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001365 /* if the compressed bits are not set in the file attributes,
1366 * then read the information from the package word count property
1367 */
James Hawkinsf80b5f62008-10-16 22:55:21 -05001368 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1369 {
1370 file->IsCompressed = FALSE;
1371 }
1372 else if (file->Attributes &
1373 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
James Hawkins98d14862006-07-31 11:15:52 -07001374 {
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001375 file->IsCompressed = TRUE;
1376 }
1377 else if (file->Attributes & msidbFileAttributesNoncompressed)
1378 {
1379 file->IsCompressed = FALSE;
1380 }
1381 else
1382 {
James Hawkins7538f9a2008-07-22 00:54:27 -05001383 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001384 }
1385
James Hawkins41607222007-11-25 18:01:19 -06001386 load_file_hash(package, file);
1387
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001388 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1389
1390 list_add_tail( &package->files, &file->entry );
Aric Stewartc5a14432005-05-18 17:46:12 +00001391
1392 return ERROR_SUCCESS;
1393}
1394
1395static UINT load_all_files(MSIPACKAGE *package)
1396{
1397 MSIQUERY * view;
Aric Stewartc5a14432005-05-18 17:46:12 +00001398 UINT rc;
1399 static const WCHAR Query[] =
1400 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001401 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1402 '`','S','e','q','u','e','n','c','e','`', 0};
Aric Stewartc5a14432005-05-18 17:46:12 +00001403
Mike McCormack9a9195d2006-07-19 17:01:07 +09001404 if (!list_empty(&package->files))
1405 return ERROR_SUCCESS;
1406
Aric Stewartc5a14432005-05-18 17:46:12 +00001407 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1408 if (rc != ERROR_SUCCESS)
1409 return ERROR_SUCCESS;
Aric Stewartc5a14432005-05-18 17:46:12 +00001410
Aric Stewart04598242005-06-23 16:43:24 +00001411 rc = MSI_IterateRecords(view, NULL, load_file, package);
Aric Stewartc5a14432005-05-18 17:46:12 +00001412 msiobj_release(&view->hdr);
1413
1414 return ERROR_SUCCESS;
1415}
1416
Mike McCormack7eb27022006-11-22 15:13:12 +09001417static UINT load_folder( MSIRECORD *row, LPVOID param )
1418{
1419 MSIPACKAGE *package = param;
Mike McCormack7eb27022006-11-22 15:13:12 +09001420 static WCHAR szEmpty[] = { 0 };
1421 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1422 MSIFOLDER *folder;
1423
1424 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1425 if (!folder)
1426 return ERROR_NOT_ENOUGH_MEMORY;
1427
1428 folder->Directory = msi_dup_record_field( row, 1 );
1429
1430 TRACE("%s\n", debugstr_w(folder->Directory));
1431
1432 p = msi_dup_record_field(row, 3);
1433
1434 /* split src and target dir */
1435 tgt_short = p;
1436 src_short = folder_split_path( p, ':' );
1437
1438 /* split the long and short paths */
1439 tgt_long = folder_split_path( tgt_short, '|' );
1440 src_long = folder_split_path( src_short, '|' );
1441
1442 /* check for no-op dirs */
1443 if (!lstrcmpW(szDot, tgt_short))
1444 tgt_short = szEmpty;
1445 if (!lstrcmpW(szDot, src_short))
1446 src_short = szEmpty;
1447
1448 if (!tgt_long)
1449 tgt_long = tgt_short;
1450
1451 if (!src_short) {
1452 src_short = tgt_short;
1453 src_long = tgt_long;
1454 }
1455
1456 if (!src_long)
1457 src_long = src_short;
1458
1459 /* FIXME: use the target short path too */
1460 folder->TargetDefault = strdupW(tgt_long);
1461 folder->SourceShortPath = strdupW(src_short);
1462 folder->SourceLongPath = strdupW(src_long);
1463 msi_free(p);
1464
1465 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1466 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1467 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1468
1469 folder->Parent = msi_dup_record_field( row, 2 );
1470
1471 folder->Property = msi_dup_property( package, folder->Directory );
1472
1473 list_add_tail( &package->folders, &folder->entry );
1474
1475 TRACE("returning %p\n", folder);
1476
1477 return ERROR_SUCCESS;
1478}
1479
1480static UINT load_all_folders( MSIPACKAGE *package )
1481{
1482 static const WCHAR query[] = {
1483 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1484 '`','D','i','r','e','c','t','o','r','y','`',0 };
1485 MSIQUERY *view;
1486 UINT r;
1487
1488 if (!list_empty(&package->folders))
1489 return ERROR_SUCCESS;
1490
1491 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1492 if (r != ERROR_SUCCESS)
1493 return r;
1494
1495 r = MSI_IterateRecords(view, NULL, load_folder, package);
1496 msiobj_release(&view->hdr);
1497 return r;
1498}
Aric Stewartc5a14432005-05-18 17:46:12 +00001499
Aric Stewartbdb29552004-07-04 00:32:48 +00001500/*
Mike McCormack9a9195d2006-07-19 17:01:07 +09001501 * I am not doing any of the costing functionality yet.
Aric Stewartbdb29552004-07-04 00:32:48 +00001502 * Mostly looking at doing the Component and Feature loading
1503 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001504 * The native MSI does A LOT of modification to tables here. Mostly adding
Mike McCormack9a9195d2006-07-19 17:01:07 +09001505 * a lot of temporary columns to the Feature and Component tables.
Aric Stewartbdb29552004-07-04 00:32:48 +00001506 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001507 * note: Native msi also tracks the short filename. But I am only going to
Aric Stewartbdb29552004-07-04 00:32:48 +00001508 * track the long ones. Also looking at this directory table
1509 * it appears that the directory table does not get the parents
Mike McCormack9a9195d2006-07-19 17:01:07 +09001510 * resolved base on property only based on their entries in the
Aric Stewartbdb29552004-07-04 00:32:48 +00001511 * directory table.
1512 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001513static UINT ACTION_CostInitialize(MSIPACKAGE *package)
Aric Stewartbdb29552004-07-04 00:32:48 +00001514{
Aric Stewart8e233e92005-03-01 11:45:19 +00001515 static const WCHAR szCosting[] =
1516 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
Aric Stewartbdb29552004-07-04 00:32:48 +00001517
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001518 MSI_SetPropertyW(package, szCosting, szZero);
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001519 MSI_SetPropertyW(package, cszRootDrive, c_colon);
Aric Stewartbdb29552004-07-04 00:32:48 +00001520
James Hawkinsdbbd5ca2008-06-10 17:33:29 -05001521 load_all_folders( package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001522 load_all_components( package );
1523 load_all_features( package );
1524 load_all_files( package );
Aric Stewartec688fb2004-07-04 00:35:52 +00001525
Aric Stewartec688fb2004-07-04 00:35:52 +00001526 return ERROR_SUCCESS;
1527}
1528
Mike McCormackf9acfe62005-06-07 20:29:51 +00001529static UINT execute_script(MSIPACKAGE *package, UINT script )
Aric Stewart9cd707d2005-05-27 19:24:22 +00001530{
James Hawkinsbb54ed12007-11-05 04:36:49 -05001531 UINT i;
Aric Stewart9cd707d2005-05-27 19:24:22 +00001532 UINT rc = ERROR_SUCCESS;
1533
1534 TRACE("Executing Script %i\n",script);
1535
Mike McCormackaa81e4f2006-01-10 12:09:19 +01001536 if (!package->script)
1537 {
1538 ERR("no script!\n");
1539 return ERROR_FUNCTION_FAILED;
1540 }
1541
Aric Stewart9cd707d2005-05-27 19:24:22 +00001542 for (i = 0; i < package->script->ActionCount[script]; i++)
1543 {
1544 LPWSTR action;
1545 action = package->script->Actions[script][i];
1546 ui_actionstart(package, action);
1547 TRACE("Executing Action (%s)\n",debugstr_w(action));
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001548 rc = ACTION_PerformAction(package, action, script, TRUE);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001549 if (rc != ERROR_SUCCESS)
1550 break;
1551 }
Mike McCormackf86cfd42006-11-02 18:12:43 +09001552 msi_free_action_script(package, script);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001553 return rc;
1554}
1555
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001556static UINT ACTION_FileCost(MSIPACKAGE *package)
Aric Stewartec688fb2004-07-04 00:35:52 +00001557{
Aric Stewartbdb29552004-07-04 00:32:48 +00001558 return ERROR_SUCCESS;
1559}
1560
Mike McCormackb7669152006-10-30 16:35:09 +09001561static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001562{
Mike McCormack38d67a42005-08-22 09:15:23 +00001563 MSICOMPONENT *comp;
James Hawkins42115632008-08-18 23:14:19 -05001564 INSTALLSTATE state;
1565 UINT r;
Aric Stewart78a04e32005-02-22 15:47:00 +00001566
James Hawkins42115632008-08-18 23:14:19 -05001567 state = MsiQueryProductStateW(package->ProductCode);
1568
1569 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
Aric Stewart78a04e32005-02-22 15:47:00 +00001570 {
James Hawkins32f57022006-09-20 19:57:03 -07001571 if (!comp->ComponentId)
1572 continue;
1573
James Hawkins42115632008-08-18 23:14:19 -05001574 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1575 comp->Installed = INSTALLSTATE_ABSENT;
1576 else
1577 {
1578 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1579 package->Context, comp->ComponentId,
1580 &comp->Installed);
1581 if (r != ERROR_SUCCESS)
1582 comp->Installed = INSTALLSTATE_ABSENT;
1583 }
Aric Stewart78a04e32005-02-22 15:47:00 +00001584 }
Mike McCormackb7669152006-10-30 16:35:09 +09001585}
1586
James Hawkins5a3c3b62008-08-18 23:14:53 -05001587static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
Mike McCormackb7669152006-10-30 16:35:09 +09001588{
Mike McCormackb7669152006-10-30 16:35:09 +09001589 MSIFEATURE *feature;
James Hawkins5a3c3b62008-08-18 23:14:53 -05001590 INSTALLSTATE state;
1591
1592 state = MsiQueryProductStateW(package->ProductCode);
Aric Stewart78a04e32005-02-22 15:47:00 +00001593
Mike McCormack1da28582005-08-22 14:09:17 +00001594 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001595 {
James Hawkins5a3c3b62008-08-18 23:14:53 -05001596 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1597 feature->Installed = INSTALLSTATE_ABSENT;
1598 else
Aric Stewart78a04e32005-02-22 15:47:00 +00001599 {
James Hawkins5a3c3b62008-08-18 23:14:53 -05001600 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1601 feature->Feature);
Aric Stewart78a04e32005-02-22 15:47:00 +00001602 }
1603 }
1604}
1605
James Hawkinsc855fbf2008-08-25 00:06:43 -05001606static BOOL process_state_property(MSIPACKAGE* package, int level,
1607 LPCWSTR property, INSTALLSTATE state)
Aric Stewartae1aa322004-12-27 19:02:59 +00001608{
Mike McCormack72faac02005-09-08 11:03:35 +00001609 LPWSTR override;
Mike McCormack1da28582005-08-22 14:09:17 +00001610 MSIFEATURE *feature;
Aric Stewartae1aa322004-12-27 19:02:59 +00001611
Mike McCormack062ad502005-09-15 15:04:08 +00001612 override = msi_dup_property( package, property );
Mike McCormack72faac02005-09-08 11:03:35 +00001613 if (!override)
1614 return FALSE;
Mike McCormack575cc672006-10-26 14:09:29 +09001615
Mike McCormack72faac02005-09-08 11:03:35 +00001616 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001617 {
Hans Leidekker843382f2009-10-15 12:46:27 +02001618 if (lstrcmpW(property, szRemove) &&
James Hawkinsc855fbf2008-08-25 00:06:43 -05001619 (feature->Level <= 0 || feature->Level > level))
1620 continue;
1621
Hans Leidekker843382f2009-10-15 12:46:27 +02001622 if (!strcmpW(property, szReinstall)) state = feature->Installed;
Hans Leidekker40cfbaf2009-03-12 11:46:35 +01001623
Hans Leidekker843382f2009-10-15 12:46:27 +02001624 if (strcmpiW(override, szAll)==0)
James Hawkinsd596ae22008-08-25 00:07:18 -05001625 msi_feature_set_state(package, feature, state);
Mike McCormack72faac02005-09-08 11:03:35 +00001626 else
1627 {
1628 LPWSTR ptr = override;
1629 LPWSTR ptr2 = strchrW(override,',');
Aric Stewartd900b532004-12-27 19:12:35 +00001630
Mike McCormack72faac02005-09-08 11:03:35 +00001631 while (ptr)
1632 {
Hans Leidekker2bfce6c2010-01-18 13:10:15 +01001633 int len = ptr2 - ptr;
1634
1635 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1636 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
Aric Stewartd900b532004-12-27 19:12:35 +00001637 {
James Hawkinsd596ae22008-08-25 00:07:18 -05001638 msi_feature_set_state(package, feature, state);
Mike McCormack72faac02005-09-08 11:03:35 +00001639 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001640 }
Mike McCormack72faac02005-09-08 11:03:35 +00001641 if (ptr2)
1642 {
1643 ptr=ptr2+1;
1644 ptr2 = strchrW(ptr,',');
1645 }
1646 else
1647 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001648 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001649 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001650 }
Mike McCormackee034ba2005-09-20 11:59:14 +00001651 msi_free(override);
Aric Stewart78a04e32005-02-22 15:47:00 +00001652
Mike McCormack72faac02005-09-08 11:03:35 +00001653 return TRUE;
Aric Stewart78a04e32005-02-22 15:47:00 +00001654}
1655
Hans Leidekker0d770c92010-01-27 11:18:02 +01001656static BOOL process_overrides( MSIPACKAGE *package, int level )
Aric Stewart78a04e32005-02-22 15:47:00 +00001657{
Aric Stewart8e233e92005-03-01 11:45:19 +00001658 static const WCHAR szAddLocal[] =
1659 {'A','D','D','L','O','C','A','L',0};
James Hawkinsc31fd432007-11-06 05:22:11 -06001660 static const WCHAR szAddSource[] =
1661 {'A','D','D','S','O','U','R','C','E',0};
Hans Leidekker4da865f2009-03-13 11:34:46 +01001662 static const WCHAR szAdvertise[] =
1663 {'A','D','V','E','R','T','I','S','E',0};
Hans Leidekker0d770c92010-01-27 11:18:02 +01001664 BOOL ret = FALSE;
1665
1666 /* all these activation/deactivation things happen in order and things
1667 * later on the list override things earlier on the list.
1668 *
1669 * 0 INSTALLLEVEL processing
1670 * 1 ADDLOCAL
1671 * 2 REMOVE
1672 * 3 ADDSOURCE
1673 * 4 ADDDEFAULT
1674 * 5 REINSTALL
1675 * 6 ADVERTISE
1676 * 7 COMPADDLOCAL
1677 * 8 COMPADDSOURCE
1678 * 9 FILEADDLOCAL
1679 * 10 FILEADDSOURCE
1680 * 11 FILEADDDEFAULT
1681 */
1682 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1683 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1684 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1685 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1686 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1687
1688 if (ret)
1689 MSI_SetPropertyW( package, szPreselected, szOne );
1690
1691 return ret;
1692}
1693
1694UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1695{
1696 int level;
1697 static const WCHAR szlevel[] =
1698 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
Mike McCormack38d67a42005-08-22 09:15:23 +00001699 MSICOMPONENT* component;
Mike McCormack1da28582005-08-22 14:09:17 +00001700 MSIFEATURE *feature;
1701
Aric Stewart78a04e32005-02-22 15:47:00 +00001702 TRACE("Checking Install Level\n");
1703
James Hawkinsc855fbf2008-08-25 00:06:43 -05001704 level = msi_get_property_int(package, szlevel, 1);
Aric Stewart78a04e32005-02-22 15:47:00 +00001705
Hans Leidekker0d770c92010-01-27 11:18:02 +01001706 if (!msi_get_property_int( package, szPreselected, 0 ))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001707 {
Mike McCormack1da28582005-08-22 14:09:17 +00001708 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001709 {
Mike McCormack1da28582005-08-22 14:09:17 +00001710 BOOL feature_state = ((feature->Level > 0) &&
James Hawkinsc855fbf2008-08-25 00:06:43 -05001711 (feature->Level <= level));
Aric Stewartae1aa322004-12-27 19:02:59 +00001712
Mike McCormack1da28582005-08-22 14:09:17 +00001713 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001714 {
Mike McCormack1da28582005-08-22 14:09:17 +00001715 if (feature->Attributes & msidbFeatureAttributesFavorSource)
James Hawkinsd596ae22008-08-25 00:07:18 -05001716 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
Mike McCormack1da28582005-08-22 14:09:17 +00001717 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
James Hawkinsd596ae22008-08-25 00:07:18 -05001718 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00001719 else
James Hawkinsd596ae22008-08-25 00:07:18 -05001720 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001721 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001722 }
James Hawkins545d0e72006-09-20 19:59:19 -07001723
1724 /* disable child features of unselected parent features */
1725 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1726 {
1727 FeatureList *fl;
1728
James Hawkinsc855fbf2008-08-25 00:06:43 -05001729 if (feature->Level > 0 && feature->Level <= level)
James Hawkins545d0e72006-09-20 19:59:19 -07001730 continue;
1731
1732 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
James Hawkinsd596ae22008-08-25 00:07:18 -05001733 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
James Hawkins545d0e72006-09-20 19:59:19 -07001734 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001735 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001736
Aric Stewartfbdd7092004-12-27 19:06:22 +00001737 /*
Mike McCormack6395ff62006-10-26 12:34:52 +09001738 * now we want to enable or disable components base on feature
1739 */
Aric Stewartfbdd7092004-12-27 19:06:22 +00001740
Mike McCormack1da28582005-08-22 14:09:17 +00001741 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001742 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001743 ComponentList *cl;
1744
James Hawkins62219752008-05-19 02:27:50 -05001745 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1746 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1747
1748 if (!feature->Level)
1749 continue;
Mike McCormack97419ae2006-12-05 18:24:39 +09001750
1751 /* features with components that have compressed files are made local */
1752 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1753 {
1754 if (cl->component->Enabled &&
1755 cl->component->ForceLocalState &&
1756 feature->Action == INSTALLSTATE_SOURCE)
1757 {
James Hawkinsd596ae22008-08-25 00:07:18 -05001758 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
Mike McCormack97419ae2006-12-05 18:24:39 +09001759 break;
1760 }
1761 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001762
Mike McCormack1da28582005-08-22 14:09:17 +00001763 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001764 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001765 component = cl->component;
Aric Stewartfbdd7092004-12-27 19:06:22 +00001766
Mike McCormack87fa8542006-11-10 15:38:51 +09001767 if (!component->Enabled)
1768 continue;
1769
Mike McCormack97419ae2006-12-05 18:24:39 +09001770 switch (feature->Action)
Mike McCormackad80ece2006-11-10 15:38:31 +09001771 {
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001772 case INSTALLSTATE_ABSENT:
1773 component->anyAbsent = 1;
1774 break;
Mike McCormack97419ae2006-12-05 18:24:39 +09001775 case INSTALLSTATE_ADVERTISED:
1776 component->hasAdvertiseFeature = 1;
1777 break;
1778 case INSTALLSTATE_SOURCE:
1779 component->hasSourceFeature = 1;
1780 break;
1781 case INSTALLSTATE_LOCAL:
1782 component->hasLocalFeature = 1;
1783 break;
1784 case INSTALLSTATE_DEFAULT:
1785 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1786 component->hasAdvertiseFeature = 1;
1787 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1788 component->hasSourceFeature = 1;
Mike McCormackad80ece2006-11-10 15:38:31 +09001789 else
Mike McCormack97419ae2006-12-05 18:24:39 +09001790 component->hasLocalFeature = 1;
1791 break;
1792 default:
1793 break;
James Hawkins929395c2006-10-19 15:51:33 -07001794 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001795 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001796 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001797
Mike McCormack38d67a42005-08-22 09:15:23 +00001798 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001799 {
Mike McCormack97419ae2006-12-05 18:24:39 +09001800 /* if the component isn't enabled, leave it alone */
1801 if (!component->Enabled)
1802 continue;
1803
1804 /* check if it's local or source */
1805 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1806 (component->hasLocalFeature || component->hasSourceFeature))
1807 {
1808 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1809 !component->ForceLocalState)
James Hawkins3bec1622008-08-25 00:07:52 -05001810 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
Mike McCormack97419ae2006-12-05 18:24:39 +09001811 else
James Hawkins3bec1622008-08-25 00:07:52 -05001812 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
Mike McCormack97419ae2006-12-05 18:24:39 +09001813 continue;
1814 }
1815
1816 /* if any feature is local, the component must be local too */
1817 if (component->hasLocalFeature)
1818 {
James Hawkins3bec1622008-08-25 00:07:52 -05001819 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
Mike McCormack97419ae2006-12-05 18:24:39 +09001820 continue;
1821 }
1822
1823 if (component->hasSourceFeature)
1824 {
James Hawkins3bec1622008-08-25 00:07:52 -05001825 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
Mike McCormack97419ae2006-12-05 18:24:39 +09001826 continue;
1827 }
1828
1829 if (component->hasAdvertiseFeature)
1830 {
James Hawkins3bec1622008-08-25 00:07:52 -05001831 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
Mike McCormack97419ae2006-12-05 18:24:39 +09001832 continue;
1833 }
1834
1835 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001836 if (component->anyAbsent)
James Hawkins3bec1622008-08-25 00:07:52 -05001837 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
Mike McCormack97419ae2006-12-05 18:24:39 +09001838 }
1839
1840 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1841 {
Mike McCormack9efb7b72006-11-07 17:55:43 +09001842 if (component->Action == INSTALLSTATE_DEFAULT)
1843 {
1844 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
James Hawkins3bec1622008-08-25 00:07:52 -05001845 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
Mike McCormack9efb7b72006-11-07 17:55:43 +09001846 }
1847
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001848 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1849 debugstr_w(component->Component), component->Installed, component->Action);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001850 }
1851
1852
Aric Stewartae1aa322004-12-27 19:02:59 +00001853 return ERROR_SUCCESS;
1854}
1855
Aric Stewart443ad4d2005-06-21 20:50:12 +00001856static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1857{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001858 MSIPACKAGE *package = param;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001859 LPCWSTR name;
1860 LPWSTR path;
James Hawkinsbaad8882007-05-01 03:19:50 -05001861 MSIFOLDER *f;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001862
1863 name = MSI_RecordGetString(row,1);
1864
James Hawkinsbaad8882007-05-01 03:19:50 -05001865 f = get_loaded_folder(package, name);
1866 if (!f) return ERROR_SUCCESS;
1867
1868 /* reset the ResolvedTarget */
1869 msi_free(f->ResolvedTarget);
1870 f->ResolvedTarget = NULL;
1871
Aric Stewart443ad4d2005-06-21 20:50:12 +00001872 /* This helper function now does ALL the work */
1873 TRACE("Dir %s ...\n",debugstr_w(name));
James Hawkins8cedb212007-03-29 02:38:57 -05001874 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001875 TRACE("resolves to %s\n",debugstr_w(path));
Mike McCormackee034ba2005-09-20 11:59:14 +00001876 msi_free(path);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001877
1878 return ERROR_SUCCESS;
1879}
1880
1881static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1882{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001883 MSIPACKAGE *package = param;
Mike McCormack1da28582005-08-22 14:09:17 +00001884 LPCWSTR name;
1885 MSIFEATURE *feature;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001886
Mike McCormack1da28582005-08-22 14:09:17 +00001887 name = MSI_RecordGetString( row, 1 );
Aric Stewart443ad4d2005-06-21 20:50:12 +00001888
Mike McCormack1da28582005-08-22 14:09:17 +00001889 feature = get_loaded_feature( package, name );
1890 if (!feature)
1891 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
Aric Stewart443ad4d2005-06-21 20:50:12 +00001892 else
1893 {
1894 LPCWSTR Condition;
1895 Condition = MSI_RecordGetString(row,3);
1896
Aric Stewart0713f092005-06-24 11:51:29 +00001897 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
Aric Stewart443ad4d2005-06-21 20:50:12 +00001898 {
1899 int level = MSI_RecordGetInteger(row,2);
Francois Gouget633ee952008-05-06 20:01:59 +02001900 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
Mike McCormack1da28582005-08-22 14:09:17 +00001901 feature->Level = level;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001902 }
1903 }
1904 return ERROR_SUCCESS;
1905}
1906
Andrew Talbot020bda72007-01-12 16:47:57 +00001907static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
Mike McCormackd1723de2006-10-24 17:37:26 +09001908{
1909 static const WCHAR name_fmt[] =
1910 {'%','u','.','%','u','.','%','u','.','%','u',0};
Dmitry Timoshkov76d6b762008-05-26 13:06:47 +09001911 static const WCHAR name[] = {'\\',0};
Mike McCormackd1723de2006-10-24 17:37:26 +09001912 VS_FIXEDFILEINFO *lpVer;
1913 WCHAR filever[0x100];
1914 LPVOID version;
1915 DWORD versize;
1916 DWORD handle;
1917 UINT sz;
1918
1919 TRACE("%s\n", debugstr_w(filename));
1920
1921 versize = GetFileVersionInfoSizeW( filename, &handle );
1922 if (!versize)
1923 return NULL;
1924
1925 version = msi_alloc( versize );
1926 GetFileVersionInfoW( filename, 0, versize, version );
1927
Rob Shearman9c6fac62007-06-26 22:22:52 +01001928 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1929 {
1930 msi_free( version );
1931 return NULL;
1932 }
Mike McCormackd1723de2006-10-24 17:37:26 +09001933
1934 sprintfW( filever, name_fmt,
1935 HIWORD(lpVer->dwFileVersionMS),
1936 LOWORD(lpVer->dwFileVersionMS),
1937 HIWORD(lpVer->dwFileVersionLS),
1938 LOWORD(lpVer->dwFileVersionLS));
1939
Rob Shearman023383a2007-06-26 22:23:30 +01001940 msi_free( version );
1941
Mike McCormackd1723de2006-10-24 17:37:26 +09001942 return strdupW( filever );
1943}
1944
Mike McCormackc5c55212006-11-07 15:05:48 +09001945static UINT msi_check_file_install_states( MSIPACKAGE *package )
Aric Stewart401bd3f2004-06-28 20:34:35 +00001946{
Mike McCormackc5c55212006-11-07 15:05:48 +09001947 LPWSTR file_version;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001948 MSIFILE *file;
Aric Stewartec688fb2004-07-04 00:35:52 +00001949
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001950 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartec688fb2004-07-04 00:35:52 +00001951 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00001952 MSICOMPONENT* comp = file->Component;
1953 LPWSTR p;
Aric Stewartec688fb2004-07-04 00:35:52 +00001954
Mike McCormackf11c8b02005-09-09 14:48:51 +00001955 if (!comp)
1956 continue;
Aric Stewartec688fb2004-07-04 00:35:52 +00001957
James Hawkinsd893cb72006-09-20 19:55:01 -07001958 if (file->IsCompressed)
James Hawkinsd893cb72006-09-20 19:55:01 -07001959 comp->ForceLocalState = TRUE;
James Hawkinsd893cb72006-09-20 19:55:01 -07001960
Mike McCormackf11c8b02005-09-09 14:48:51 +00001961 /* calculate target */
James Hawkins8cedb212007-03-29 02:38:57 -05001962 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
Mike McCormackf11c8b02005-09-09 14:48:51 +00001963
Mike McCormackee034ba2005-09-20 11:59:14 +00001964 msi_free(file->TargetPath);
Mike McCormackf11c8b02005-09-09 14:48:51 +00001965
1966 TRACE("file %s is named %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09001967 debugstr_w(file->File), debugstr_w(file->FileName));
Mike McCormackf11c8b02005-09-09 14:48:51 +00001968
1969 file->TargetPath = build_directory_name(2, p, file->FileName);
1970
Mike McCormackee034ba2005-09-20 11:59:14 +00001971 msi_free(p);
Mike McCormackf11c8b02005-09-09 14:48:51 +00001972
1973 TRACE("file %s resolves to %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09001974 debugstr_w(file->File), debugstr_w(file->TargetPath));
Mike McCormackf11c8b02005-09-09 14:48:51 +00001975
Mike McCormackddf0b592006-10-31 14:32:48 +09001976 /* don't check files of components that aren't installed */
1977 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1978 comp->Installed == INSTALLSTATE_ABSENT)
1979 {
1980 file->state = msifs_missing; /* assume files are missing */
1981 continue;
1982 }
1983
Mike McCormackf11c8b02005-09-09 14:48:51 +00001984 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
Aric Stewartec688fb2004-07-04 00:35:52 +00001985 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00001986 file->state = msifs_missing;
Mike McCormackf11c8b02005-09-09 14:48:51 +00001987 comp->Cost += file->FileSize;
1988 continue;
1989 }
Mike McCormackba8200b2004-12-22 15:25:30 +00001990
Mike McCormackd1723de2006-10-24 17:37:26 +09001991 if (file->Version &&
1992 (file_version = msi_get_disk_file_version( file->TargetPath )))
Mike McCormackf11c8b02005-09-09 14:48:51 +00001993 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00001994 TRACE("new %s old %s\n", debugstr_w(file->Version),
Mike McCormackd1723de2006-10-24 17:37:26 +09001995 debugstr_w(file_version));
1996 /* FIXME: seems like a bad way to compare version numbers */
1997 if (lstrcmpiW(file_version, file->Version)<0)
Aric Stewartec688fb2004-07-04 00:35:52 +00001998 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00001999 file->state = msifs_overwrite;
Aric Stewartec688fb2004-07-04 00:35:52 +00002000 comp->Cost += file->FileSize;
2001 }
2002 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002003 file->state = msifs_present;
Mike McCormackd1723de2006-10-24 17:37:26 +09002004 msi_free( file_version );
Mike McCormackf11c8b02005-09-09 14:48:51 +00002005 }
2006 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002007 file->state = msifs_present;
Aric Stewartec688fb2004-07-04 00:35:52 +00002008 }
2009
Mike McCormackc5c55212006-11-07 15:05:48 +09002010 return ERROR_SUCCESS;
2011}
2012
2013/*
2014 * A lot is done in this function aside from just the costing.
2015 * The costing needs to be implemented at some point but for now I am going
2016 * to focus on the directory building
2017 *
2018 */
2019static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2020{
2021 static const WCHAR ExecSeqQuery[] =
2022 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2023 '`','D','i','r','e','c','t','o','r','y','`',0};
2024 static const WCHAR ConditionQuery[] =
2025 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2026 '`','C','o','n','d','i','t','i','o','n','`',0};
2027 static const WCHAR szCosting[] =
2028 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2029 static const WCHAR szlevel[] =
2030 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
James Hawkinsece5a042008-05-13 20:31:44 -05002031 static const WCHAR szOutOfDiskSpace[] =
2032 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
Mike McCormackc5c55212006-11-07 15:05:48 +09002033 MSICOMPONENT *comp;
Hans Leidekker0d770c92010-01-27 11:18:02 +01002034 UINT rc = ERROR_SUCCESS;
Mike McCormackc5c55212006-11-07 15:05:48 +09002035 MSIQUERY * view;
2036 LPWSTR level;
2037
Mike McCormackc5c55212006-11-07 15:05:48 +09002038 TRACE("Building Directory properties\n");
2039
2040 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2041 if (rc == ERROR_SUCCESS)
2042 {
2043 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2044 package);
2045 msiobj_release(&view->hdr);
2046 }
2047
2048 /* read components states from the registry */
2049 ACTION_GetComponentInstallStates(package);
James Hawkins5a3c3b62008-08-18 23:14:53 -05002050 ACTION_GetFeatureInstallStates(package);
Mike McCormackc5c55212006-11-07 15:05:48 +09002051
2052 TRACE("File calculations\n");
2053 msi_check_file_install_states( package );
2054
Hans Leidekker0d770c92010-01-27 11:18:02 +01002055 if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) ))
Aric Stewart84837d92004-07-20 01:22:37 +00002056 {
Hans Leidekker0d770c92010-01-27 11:18:02 +01002057 TRACE("Evaluating Condition Table\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002058
Hans Leidekker0d770c92010-01-27 11:18:02 +01002059 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2060 if (rc == ERROR_SUCCESS)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002061 {
Hans Leidekker0d770c92010-01-27 11:18:02 +01002062 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2063 msiobj_release( &view->hdr );
Aric Stewart7d3e5972004-07-04 00:36:58 +00002064 }
Hans Leidekker0d770c92010-01-27 11:18:02 +01002065
2066 TRACE("Enabling or Disabling Components\n");
2067 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2068 {
2069 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2070 {
2071 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2072 comp->Enabled = FALSE;
2073 }
2074 else
2075 comp->Enabled = TRUE;
2076 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002077 }
2078
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002079 MSI_SetPropertyW(package,szCosting,szOne);
Aric Stewart8cc14a92004-12-27 18:56:30 +00002080 /* set default run level if not set */
Mike McCormack062ad502005-09-15 15:04:08 +00002081 level = msi_dup_property( package, szlevel );
Aric Stewart8cc14a92004-12-27 18:56:30 +00002082 if (!level)
2083 MSI_SetPropertyW(package,szlevel, szOne);
Mike McCormackee034ba2005-09-20 11:59:14 +00002084 msi_free(level);
Aric Stewartae1aa322004-12-27 19:02:59 +00002085
James Hawkinsece5a042008-05-13 20:31:44 -05002086 /* FIXME: check volume disk space */
2087 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2088
James Hawkins7c7f0bb2006-07-19 11:15:37 -07002089 return MSI_SetFeatureStates(package);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002090}
2091
Francois Gougetda8b3dd2005-01-26 21:09:04 +00002092/* OK this value is "interpreted" and then formatted based on the
Aric Stewart6e160f12004-06-29 04:07:22 +00002093 first few characters */
Aric Stewart09b0aba2005-06-09 20:30:59 +00002094static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
Aric Stewart401bd3f2004-06-28 20:34:35 +00002095 DWORD *size)
2096{
2097 LPSTR data = NULL;
James Hawkins2f658cb2008-02-04 19:06:53 -06002098
Aric Stewart6e160f12004-06-29 04:07:22 +00002099 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
Aric Stewart401bd3f2004-06-28 20:34:35 +00002100 {
Aric Stewart6e160f12004-06-29 04:07:22 +00002101 if (value[1]=='x')
2102 {
2103 LPWSTR ptr;
2104 CHAR byte[5];
Aric Stewart6186b2b2005-05-16 21:37:35 +00002105 LPWSTR deformated = NULL;
Aric Stewart6e160f12004-06-29 04:07:22 +00002106 int count;
2107
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002108 deformat_string(package, &value[2], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002109
2110 /* binary value type */
Aric Stewart6186b2b2005-05-16 21:37:35 +00002111 ptr = deformated;
2112 *type = REG_BINARY;
2113 if (strlenW(ptr)%2)
2114 *size = (strlenW(ptr)/2)+1;
2115 else
2116 *size = strlenW(ptr)/2;
2117
Mike McCormackee034ba2005-09-20 11:59:14 +00002118 data = msi_alloc(*size);
Aric Stewart6186b2b2005-05-16 21:37:35 +00002119
Aric Stewart6e160f12004-06-29 04:07:22 +00002120 byte[0] = '0';
2121 byte[1] = 'x';
2122 byte[4] = 0;
2123 count = 0;
Aric Stewart6186b2b2005-05-16 21:37:35 +00002124 /* if uneven pad with a zero in front */
2125 if (strlenW(ptr)%2)
2126 {
2127 byte[2]= '0';
2128 byte[3]= *ptr;
2129 ptr++;
2130 data[count] = (BYTE)strtol(byte,NULL,0);
2131 count ++;
2132 TRACE("Uneven byte count\n");
2133 }
Aric Stewart6e160f12004-06-29 04:07:22 +00002134 while (*ptr)
2135 {
2136 byte[2]= *ptr;
2137 ptr++;
2138 byte[3]= *ptr;
2139 ptr++;
2140 data[count] = (BYTE)strtol(byte,NULL,0);
2141 count ++;
2142 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002143 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002144
Mike McCormackf1d46462006-10-05 13:41:22 +09002145 TRACE("Data %i bytes(%i)\n",*size,count);
Aric Stewart6e160f12004-06-29 04:07:22 +00002146 }
2147 else
2148 {
2149 LPWSTR deformated;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002150 LPWSTR p;
2151 DWORD d = 0;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002152 deformat_string(package, &value[1], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002153
2154 *type=REG_DWORD;
2155 *size = sizeof(DWORD);
Mike McCormackee034ba2005-09-20 11:59:14 +00002156 data = msi_alloc(*size);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002157 p = deformated;
2158 if (*p == '-')
2159 p++;
2160 while (*p)
2161 {
2162 if ( (*p < '0') || (*p > '9') )
2163 break;
2164 d *= 10;
2165 d += (*p - '0');
2166 p++;
2167 }
2168 if (deformated[0] == '-')
2169 d = -d;
2170 *(LPDWORD)data = d;
Mike McCormackf1d46462006-10-05 13:41:22 +09002171 TRACE("DWORD %i\n",*(LPDWORD)data);
Aric Stewart6e160f12004-06-29 04:07:22 +00002172
Mike McCormackee034ba2005-09-20 11:59:14 +00002173 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002174 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002175 }
2176 else
2177 {
Aric Stewart54c67dd2005-01-25 20:17:09 +00002178 static const WCHAR szMulti[] = {'[','~',']',0};
Aric Stewart09b0aba2005-06-09 20:30:59 +00002179 LPCWSTR ptr;
Aric Stewart6e160f12004-06-29 04:07:22 +00002180 *type=REG_SZ;
2181
Aric Stewart401bd3f2004-06-28 20:34:35 +00002182 if (value[0]=='#')
Aric Stewart6e160f12004-06-29 04:07:22 +00002183 {
2184 if (value[1]=='%')
2185 {
2186 ptr = &value[2];
2187 *type=REG_EXPAND_SZ;
2188 }
2189 else
2190 ptr = &value[1];
2191 }
2192 else
Aric Stewart401bd3f2004-06-28 20:34:35 +00002193 ptr=value;
2194
Aric Stewart54c67dd2005-01-25 20:17:09 +00002195 if (strstrW(value,szMulti))
2196 *type = REG_MULTI_SZ;
2197
James Hawkins2f658cb2008-02-04 19:06:53 -06002198 /* remove initial delimiter */
2199 if (!strncmpW(value, szMulti, 3))
2200 ptr = value + 3;
2201
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002202 *size = deformat_string(package, ptr,(LPWSTR*)&data);
James Hawkins2f658cb2008-02-04 19:06:53 -06002203
2204 /* add double NULL terminator */
2205 if (*type == REG_MULTI_SZ)
2206 {
James Hawkins21b4af12008-02-24 20:15:31 -06002207 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2208 data = msi_realloc_zero(data, *size);
James Hawkins2f658cb2008-02-04 19:06:53 -06002209 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002210 }
2211 return data;
2212}
2213
Hans Leidekker342f8662010-02-25 15:17:11 +01002214static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2215{
2216 const WCHAR *ret;
2217
2218 switch (root)
2219 {
2220 case -1:
2221 if (msi_get_property_int( package, szAllUsers, 0 ))
2222 {
2223 *root_key = HKEY_LOCAL_MACHINE;
2224 ret = szHLM;
2225 }
2226 else
2227 {
2228 *root_key = HKEY_CURRENT_USER;
2229 ret = szHCU;
2230 }
2231 break;
2232 case 0:
2233 *root_key = HKEY_CLASSES_ROOT;
2234 ret = szHCR;
2235 break;
2236 case 1:
2237 *root_key = HKEY_CURRENT_USER;
2238 ret = szHCU;
2239 break;
2240 case 2:
2241 *root_key = HKEY_LOCAL_MACHINE;
2242 ret = szHLM;
2243 break;
2244 case 3:
2245 *root_key = HKEY_USERS;
2246 ret = szHU;
2247 break;
2248 default:
2249 ERR("Unknown root %i\n", root);
2250 return NULL;
2251 }
2252
2253 return ret;
2254}
2255
Aric Stewart92ef78e2005-06-21 20:21:18 +00002256static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2257{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01002258 MSIPACKAGE *package = param;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002259 LPSTR value_data = NULL;
2260 HKEY root_key, hkey;
2261 DWORD type,size;
2262 LPWSTR deformated;
2263 LPCWSTR szRoot, component, name, key, value;
Mike McCormack38d67a42005-08-22 09:15:23 +00002264 MSICOMPONENT *comp;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002265 MSIRECORD * uirow;
2266 LPWSTR uikey;
2267 INT root;
2268 BOOL check_first = FALSE;
2269 UINT rc;
2270
2271 ui_progress(package,2,0,0,0);
2272
2273 value = NULL;
2274 key = NULL;
2275 uikey = NULL;
2276 name = NULL;
2277
2278 component = MSI_RecordGetString(row, 6);
Mike McCormack38d67a42005-08-22 09:15:23 +00002279 comp = get_loaded_component(package,component);
Johan Dahlin0946c422005-08-24 10:57:27 +00002280 if (!comp)
2281 return ERROR_SUCCESS;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002282
Hans Leidekker598c5422010-02-16 11:44:47 +01002283 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart92ef78e2005-06-21 20:21:18 +00002284 {
Hans Leidekker598c5422010-02-16 11:44:47 +01002285 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00002286 comp->Action = comp->Installed;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002287 return ERROR_SUCCESS;
2288 }
Mike McCormack38d67a42005-08-22 09:15:23 +00002289 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002290
2291 name = MSI_RecordGetString(row, 4);
2292 if( MSI_RecordIsNull(row,5) && name )
2293 {
2294 /* null values can have special meanings */
2295 if (name[0]=='-' && name[1] == 0)
2296 return ERROR_SUCCESS;
2297 else if ((name[0]=='+' && name[1] == 0) ||
2298 (name[0] == '*' && name[1] == 0))
2299 name = NULL;
2300 check_first = TRUE;
2301 }
2302
2303 root = MSI_RecordGetInteger(row,2);
2304 key = MSI_RecordGetString(row, 3);
2305
Hans Leidekker342f8662010-02-25 15:17:11 +01002306 szRoot = get_root_key( package, root, &root_key );
2307 if (!szRoot)
Aric Stewart92ef78e2005-06-21 20:21:18 +00002308 return ERROR_SUCCESS;
2309
2310 deformat_string(package, key , &deformated);
2311 size = strlenW(deformated) + strlenW(szRoot) + 1;
Mike McCormackee034ba2005-09-20 11:59:14 +00002312 uikey = msi_alloc(size*sizeof(WCHAR));
Aric Stewart92ef78e2005-06-21 20:21:18 +00002313 strcpyW(uikey,szRoot);
2314 strcatW(uikey,deformated);
2315
2316 if (RegCreateKeyW( root_key, deformated, &hkey))
2317 {
2318 ERR("Could not create key %s\n",debugstr_w(deformated));
Mike McCormackee034ba2005-09-20 11:59:14 +00002319 msi_free(deformated);
2320 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002321 return ERROR_SUCCESS;
2322 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002323 msi_free(deformated);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002324
2325 value = MSI_RecordGetString(row,5);
2326 if (value)
2327 value_data = parse_value(package, value, &type, &size);
2328 else
2329 {
Aric Stewart92ef78e2005-06-21 20:21:18 +00002330 value_data = (LPSTR)strdupW(szEmpty);
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02002331 size = sizeof(szEmpty);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002332 type = REG_SZ;
2333 }
2334
2335 deformat_string(package, name, &deformated);
2336
Aric Stewart92ef78e2005-06-21 20:21:18 +00002337 if (!check_first)
2338 {
2339 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2340 debugstr_w(uikey));
Mike McCormack16466af2005-07-06 10:33:30 +00002341 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002342 }
2343 else
2344 {
2345 DWORD sz = 0;
2346 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2347 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2348 {
2349 TRACE("value %s of %s checked already exists\n",
2350 debugstr_w(deformated), debugstr_w(uikey));
2351 }
2352 else
2353 {
2354 TRACE("Checked and setting value %s of %s\n",
2355 debugstr_w(deformated), debugstr_w(uikey));
2356 if (deformated || size)
Mike McCormack16466af2005-07-06 10:33:30 +00002357 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002358 }
2359 }
2360 RegCloseKey(hkey);
2361
2362 uirow = MSI_CreateRecord(3);
2363 MSI_RecordSetStringW(uirow,2,deformated);
2364 MSI_RecordSetStringW(uirow,1,uikey);
Hans Leidekkerd0856c02010-03-23 11:47:42 +01002365 if (type == REG_SZ || type == REG_EXPAND_SZ)
Aric Stewart92ef78e2005-06-21 20:21:18 +00002366 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002367 ui_actiondata(package,szWriteRegistryValues,uirow);
2368 msiobj_release( &uirow->hdr );
2369
Mike McCormackee034ba2005-09-20 11:59:14 +00002370 msi_free(value_data);
2371 msi_free(deformated);
2372 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002373
2374 return ERROR_SUCCESS;
2375}
2376
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002377static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00002378{
2379 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002380 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002381 static const WCHAR ExecSeqQuery[] =
2382 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002383 '`','R','e','g','i','s','t','r','y','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00002384
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002385 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002386 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002387 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00002388
Aric Stewartd2c395a2004-07-06 18:48:15 +00002389 /* increment progress bar each time action data is sent */
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002390 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002391
Aric Stewart92ef78e2005-06-21 20:21:18 +00002392 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002393
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002394 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002395 return rc;
2396}
2397
Hans Leidekker342f8662010-02-25 15:17:11 +01002398static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2399{
2400 LONG res;
2401 HKEY hkey;
2402 DWORD num_subkeys, num_values;
2403
2404 if (delete_key)
2405 {
2406 if ((res = RegDeleteTreeW( hkey_root, key )))
2407 {
2408 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2409 }
2410 return;
2411 }
2412
2413 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2414 {
2415 if ((res = RegDeleteValueW( hkey, value )))
2416 {
2417 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2418 }
2419 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2420 NULL, NULL, NULL, NULL );
2421 RegCloseKey( hkey );
2422
2423 if (!res && !num_subkeys && !num_values)
2424 {
2425 TRACE("Removing empty key %s\n", debugstr_w(key));
2426 RegDeleteKeyW( hkey_root, key );
2427 }
2428 return;
2429 }
2430 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2431}
2432
2433
2434static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2435{
2436 MSIPACKAGE *package = param;
2437 LPCWSTR component, name, key_str, root_key_str;
2438 LPWSTR deformated_key, deformated_name, ui_key_str;
2439 MSICOMPONENT *comp;
2440 MSIRECORD *uirow;
2441 BOOL delete_key = FALSE;
2442 HKEY hkey_root;
2443 UINT size;
2444 INT root;
2445
2446 ui_progress( package, 2, 0, 0, 0 );
2447
2448 component = MSI_RecordGetString( row, 6 );
2449 comp = get_loaded_component( package, component );
2450 if (!comp)
2451 return ERROR_SUCCESS;
2452
2453 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2454 {
2455 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2456 comp->Action = comp->Installed;
2457 return ERROR_SUCCESS;
2458 }
2459 comp->Action = INSTALLSTATE_ABSENT;
2460
2461 name = MSI_RecordGetString( row, 4 );
2462 if (MSI_RecordIsNull( row, 5 ) && name )
2463 {
2464 if (name[0] == '+' && !name[1])
2465 return ERROR_SUCCESS;
2466 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2467 {
2468 delete_key = TRUE;
2469 name = NULL;
2470 }
2471 }
2472
2473 root = MSI_RecordGetInteger( row, 2 );
2474 key_str = MSI_RecordGetString( row, 3 );
2475
2476 root_key_str = get_root_key( package, root, &hkey_root );
2477 if (!root_key_str)
2478 return ERROR_SUCCESS;
2479
2480 deformat_string( package, key_str, &deformated_key );
2481 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2482 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2483 strcpyW( ui_key_str, root_key_str );
2484 strcatW( ui_key_str, deformated_key );
2485
2486 deformat_string( package, name, &deformated_name );
2487
2488 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2489 msi_free( deformated_key );
2490
2491 uirow = MSI_CreateRecord( 2 );
2492 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2493 MSI_RecordSetStringW( uirow, 2, deformated_name );
2494
2495 ui_actiondata( package, szRemoveRegistryValues, uirow );
2496 msiobj_release( &uirow->hdr );
2497
2498 msi_free( ui_key_str );
2499 msi_free( deformated_name );
2500 return ERROR_SUCCESS;
2501}
2502
2503static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2504{
2505 MSIPACKAGE *package = param;
2506 LPCWSTR component, name, key_str, root_key_str;
2507 LPWSTR deformated_key, deformated_name, ui_key_str;
2508 MSICOMPONENT *comp;
2509 MSIRECORD *uirow;
2510 BOOL delete_key = FALSE;
2511 HKEY hkey_root;
2512 UINT size;
2513 INT root;
2514
2515 ui_progress( package, 2, 0, 0, 0 );
2516
2517 component = MSI_RecordGetString( row, 5 );
2518 comp = get_loaded_component( package, component );
2519 if (!comp)
2520 return ERROR_SUCCESS;
2521
2522 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2523 {
2524 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2525 comp->Action = comp->Installed;
2526 return ERROR_SUCCESS;
2527 }
2528 comp->Action = INSTALLSTATE_LOCAL;
2529
2530 if ((name = MSI_RecordGetString( row, 4 )))
2531 {
2532 if (name[0] == '-' && !name[1])
2533 {
2534 delete_key = TRUE;
2535 name = NULL;
2536 }
2537 }
2538
2539 root = MSI_RecordGetInteger( row, 2 );
2540 key_str = MSI_RecordGetString( row, 3 );
2541
2542 root_key_str = get_root_key( package, root, &hkey_root );
2543 if (!root_key_str)
2544 return ERROR_SUCCESS;
2545
2546 deformat_string( package, key_str, &deformated_key );
2547 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2548 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2549 strcpyW( ui_key_str, root_key_str );
2550 strcatW( ui_key_str, deformated_key );
2551
2552 deformat_string( package, name, &deformated_name );
2553
2554 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2555 msi_free( deformated_key );
2556
2557 uirow = MSI_CreateRecord( 2 );
2558 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2559 MSI_RecordSetStringW( uirow, 2, deformated_name );
2560
2561 ui_actiondata( package, szRemoveRegistryValues, uirow );
2562 msiobj_release( &uirow->hdr );
2563
2564 msi_free( ui_key_str );
2565 msi_free( deformated_name );
2566 return ERROR_SUCCESS;
2567}
2568
2569static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2570{
2571 UINT rc;
2572 MSIQUERY *view;
2573 static const WCHAR registry_query[] =
2574 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2575 '`','R','e','g','i','s','t','r','y','`',0 };
2576 static const WCHAR remove_registry_query[] =
2577 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2578 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2579
2580 /* increment progress bar each time action data is sent */
2581 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2582
2583 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2584 if (rc == ERROR_SUCCESS)
2585 {
2586 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2587 msiobj_release( &view->hdr );
2588 if (rc != ERROR_SUCCESS)
2589 return rc;
2590 }
2591
2592 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2593 if (rc == ERROR_SUCCESS)
2594 {
2595 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2596 msiobj_release( &view->hdr );
2597 if (rc != ERROR_SUCCESS)
2598 return rc;
2599 }
2600
2601 return ERROR_SUCCESS;
2602}
2603
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002604static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002605{
Aric Stewart9cd707d2005-05-27 19:24:22 +00002606 package->script->CurrentlyScripting = TRUE;
2607
Aric Stewart7d3e5972004-07-04 00:36:58 +00002608 return ERROR_SUCCESS;
2609}
2610
Aric Stewartae1aa322004-12-27 19:02:59 +00002611
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002612static UINT ACTION_InstallValidate(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002613{
Mike McCormack38d67a42005-08-22 09:15:23 +00002614 MSICOMPONENT *comp;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002615 DWORD progress = 0;
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002616 DWORD total = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002617 static const WCHAR q1[]=
2618 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002619 '`','R','e','g','i','s','t','r','y','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002620 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002621 MSIQUERY * view;
Mike McCormack1da28582005-08-22 14:09:17 +00002622 MSIFEATURE *feature;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002623 MSIFILE *file;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002624
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002625 TRACE("InstallValidate\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002626
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002627 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002628 if (rc == ERROR_SUCCESS)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002629 {
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002630 MSI_IterateRecords( view, &progress, NULL, package );
2631 msiobj_release( &view->hdr );
2632 total += progress * REG_PROGRESS_VALUE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002633 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002634
Mike McCormack38d67a42005-08-22 09:15:23 +00002635 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Mike McCormack38d67a42005-08-22 09:15:23 +00002636 total += COMPONENT_PROGRESS_VALUE;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002637
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002638 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002639 total += file->FileSize;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002640
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002641 ui_progress(package,0,total,0,0);
Aric Stewart7d3e5972004-07-04 00:36:58 +00002642
Mike McCormack1da28582005-08-22 14:09:17 +00002643 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002644 {
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002645 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2646 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2647 feature->ActionRequest);
2648 }
2649
Aric Stewart7d3e5972004-07-04 00:36:58 +00002650 return ERROR_SUCCESS;
2651}
2652
Aric Stewartc79f4e22005-06-22 18:03:08 +00002653static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2654{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01002655 MSIPACKAGE* package = param;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002656 LPCWSTR cond = NULL;
2657 LPCWSTR message = NULL;
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002658 UINT r;
2659
Aric Stewartc79f4e22005-06-22 18:03:08 +00002660 static const WCHAR title[]=
2661 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2662
2663 cond = MSI_RecordGetString(row,1);
2664
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002665 r = MSI_EvaluateConditionW(package,cond);
2666 if (r == MSICONDITION_FALSE)
Aric Stewartc79f4e22005-06-22 18:03:08 +00002667 {
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002668 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2669 {
2670 LPWSTR deformated;
2671 message = MSI_RecordGetString(row,2);
2672 deformat_string(package,message,&deformated);
2673 MessageBoxW(NULL,deformated,title,MB_OK);
2674 msi_free(deformated);
2675 }
2676
2677 return ERROR_INSTALL_FAILURE;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002678 }
2679
2680 return ERROR_SUCCESS;
2681}
2682
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002683static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
Aric Stewart5b936ca2004-07-06 18:47:09 +00002684{
2685 UINT rc;
Mike McCormackf3c8b832004-07-19 19:35:05 +00002686 MSIQUERY * view = NULL;
Aric Stewart8e233e92005-03-01 11:45:19 +00002687 static const WCHAR ExecSeqQuery[] =
2688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002689 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002690
Aric Stewart5b936ca2004-07-06 18:47:09 +00002691 TRACE("Checking launch conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002692
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002693 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart5b936ca2004-07-06 18:47:09 +00002694 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002695 return ERROR_SUCCESS;
Aric Stewart5b936ca2004-07-06 18:47:09 +00002696
Aric Stewartc79f4e22005-06-22 18:03:08 +00002697 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002698 msiobj_release(&view->hdr);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002699
Aric Stewart5b936ca2004-07-06 18:47:09 +00002700 return rc;
2701}
Aric Stewart7d3e5972004-07-04 00:36:58 +00002702
Mike McCormack38d67a42005-08-22 09:15:23 +00002703static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
Aric Stewartb942e182004-07-06 18:50:02 +00002704{
Aric Stewartb942e182004-07-06 18:50:02 +00002705
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002706 if (!cmp->KeyPath)
James Hawkins8cedb212007-03-29 02:38:57 -05002707 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002708
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002709 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
Aric Stewartb942e182004-07-06 18:50:02 +00002710 {
Aric Stewart6269f002005-01-17 13:40:39 +00002711 MSIRECORD * row = 0;
Mike McCormack0b352c72005-06-02 10:29:57 +00002712 UINT root,len;
Aric Stewart09b0aba2005-06-09 20:30:59 +00002713 LPWSTR deformated,buffer,deformated_name;
2714 LPCWSTR key,name;
Aric Stewart8e233e92005-03-01 11:45:19 +00002715 static const WCHAR ExecSeqQuery[] =
2716 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002717 '`','R','e','g','i','s','t','r','y','`',' ',
2718 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2719 ' ','=',' ' ,'\'','%','s','\'',0 };
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002720 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00002721 static const WCHAR fmt2[]=
2722 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
Aric Stewart6269f002005-01-17 13:40:39 +00002723
Mike McCormack0b352c72005-06-02 10:29:57 +00002724 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2725 if (!row)
Aric Stewart6269f002005-01-17 13:40:39 +00002726 return NULL;
2727
Aric Stewart6269f002005-01-17 13:40:39 +00002728 root = MSI_RecordGetInteger(row,2);
Aric Stewart09b0aba2005-06-09 20:30:59 +00002729 key = MSI_RecordGetString(row, 3);
2730 name = MSI_RecordGetString(row, 4);
Aric Stewart6269f002005-01-17 13:40:39 +00002731 deformat_string(package, key , &deformated);
2732 deformat_string(package, name, &deformated_name);
2733
Ulrich Czekallae15e5172005-03-08 16:44:51 +00002734 len = strlenW(deformated) + 6;
Aric Stewart6269f002005-01-17 13:40:39 +00002735 if (deformated_name)
2736 len+=strlenW(deformated_name);
2737
Mike McCormackee034ba2005-09-20 11:59:14 +00002738 buffer = msi_alloc( len *sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00002739
2740 if (deformated_name)
2741 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2742 else
2743 sprintfW(buffer,fmt,root,deformated);
2744
Mike McCormackee034ba2005-09-20 11:59:14 +00002745 msi_free(deformated);
2746 msi_free(deformated_name);
Aric Stewart6269f002005-01-17 13:40:39 +00002747 msiobj_release(&row->hdr);
Aric Stewart6269f002005-01-17 13:40:39 +00002748
2749 return buffer;
2750 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002751 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewart6269f002005-01-17 13:40:39 +00002752 {
2753 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
Aric Stewartfa384f62004-12-22 18:46:17 +00002754 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002755 }
2756 else
2757 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002758 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
Aric Stewartfcb20c52004-07-06 18:51:16 +00002759
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002760 if (file)
2761 return strdupW( file->TargetPath );
Aric Stewartb942e182004-07-06 18:50:02 +00002762 }
Aric Stewartfa384f62004-12-22 18:46:17 +00002763 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002764}
2765
Stefan Huehnerac6f5622005-06-20 14:18:03 +00002766static HKEY openSharedDLLsKey(void)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002767{
2768 HKEY hkey=0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002769 static const WCHAR path[] =
2770 {'S','o','f','t','w','a','r','e','\\',
2771 'M','i','c','r','o','s','o','f','t','\\',
2772 'W','i','n','d','o','w','s','\\',
2773 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2774 'S','h','a','r','e','d','D','L','L','s',0};
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002775
2776 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2777 return hkey;
2778}
2779
2780static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2781{
2782 HKEY hkey;
2783 DWORD count=0;
2784 DWORD type;
2785 DWORD sz = sizeof(count);
2786 DWORD rc;
2787
2788 hkey = openSharedDLLsKey();
2789 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2790 if (rc != ERROR_SUCCESS)
2791 count = 0;
2792 RegCloseKey(hkey);
2793 return count;
2794}
2795
2796static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2797{
2798 HKEY hkey;
2799
2800 hkey = openSharedDLLsKey();
2801 if (count > 0)
Mike McCormack4db02cd2005-09-15 14:58:38 +00002802 msi_reg_set_val_dword( hkey, path, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002803 else
2804 RegDeleteValueW(hkey,path);
2805 RegCloseKey(hkey);
2806 return count;
2807}
2808
2809/*
2810 * Return TRUE if the count should be written out and FALSE if not
2811 */
Mike McCormack38d67a42005-08-22 09:15:23 +00002812static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002813{
Mike McCormack1da28582005-08-22 14:09:17 +00002814 MSIFEATURE *feature;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002815 INT count = 0;
2816 BOOL write = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002817
2818 /* only refcount DLLs */
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002819 if (comp->KeyPath == NULL ||
Mike McCormack38d67a42005-08-22 09:15:23 +00002820 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2821 comp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002822 write = FALSE;
2823 else
2824 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002825 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002826 write = (count > 0);
2827
Mike McCormack38d67a42005-08-22 09:15:23 +00002828 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002829 write = TRUE;
2830 }
2831
2832 /* increment counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002833 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002834 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002835 ComponentList *cl;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002836
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01002837 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002838 continue;
2839
Mike McCormack1da28582005-08-22 14:09:17 +00002840 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002841 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002842 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002843 count++;
2844 }
2845 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002846
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002847 /* decrement counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002848 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002849 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002850 ComponentList *cl;
2851
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01002852 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002853 continue;
2854
Mike McCormack1da28582005-08-22 14:09:17 +00002855 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002856 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002857 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002858 count--;
2859 }
2860 }
2861
2862 /* ref count all the files in the component */
2863 if (write)
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002864 {
2865 MSIFILE *file;
2866
2867 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002868 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002869 if (file->Component == comp)
2870 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002871 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002872 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002873
Austin English5644f052008-04-07 14:44:23 -05002874 /* add a count for permanent */
Mike McCormack38d67a42005-08-22 09:15:23 +00002875 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002876 count ++;
2877
Mike McCormack38d67a42005-08-22 09:15:23 +00002878 comp->RefCount = count;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002879
2880 if (write)
Mike McCormack38d67a42005-08-22 09:15:23 +00002881 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002882}
2883
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002884static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
Aric Stewartb942e182004-07-06 18:50:02 +00002885{
Aric Stewart68b07492005-01-25 11:05:37 +00002886 WCHAR squished_pc[GUID_SIZE];
2887 WCHAR squished_cc[GUID_SIZE];
Aric Stewartb942e182004-07-06 18:50:02 +00002888 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00002889 MSICOMPONENT *comp;
James Hawkins4aa3a992008-06-18 00:49:42 -05002890 HKEY hkey;
Aric Stewartb942e182004-07-06 18:50:02 +00002891
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002892 TRACE("\n");
2893
Aric Stewartadaef112005-07-07 20:27:06 +00002894 squash_guid(package->ProductCode,squished_pc);
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002895 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
Mike McCormack38d67a42005-08-22 09:15:23 +00002896
2897 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewartb942e182004-07-06 18:50:02 +00002898 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002899 MSIRECORD * uirow;
2900
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002901 ui_progress(package,2,0,0,0);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002902 if (!comp->ComponentId)
2903 continue;
Aric Stewartb942e182004-07-06 18:50:02 +00002904
Mike McCormackfe8cd382006-03-09 14:21:37 +09002905 squash_guid(comp->ComponentId,squished_cc);
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002906
Mike McCormackfe8cd382006-03-09 14:21:37 +09002907 msi_free(comp->FullKeypath);
2908 comp->FullKeypath = resolve_keypath( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002909
Mike McCormackfe8cd382006-03-09 14:21:37 +09002910 ACTION_RefCountComponent( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002911
Mike McCormackfe8cd382006-03-09 14:21:37 +09002912 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
Mike McCormack38d67a42005-08-22 09:15:23 +00002913 debugstr_w(comp->Component),
Aric Stewartc5a14432005-05-18 17:46:12 +00002914 debugstr_w(squished_cc),
Mike McCormackfe8cd382006-03-09 14:21:37 +09002915 debugstr_w(comp->FullKeypath),
Mike McCormack38d67a42005-08-22 09:15:23 +00002916 comp->RefCount);
James Hawkins96dd6ce2008-08-21 02:14:26 -05002917
Hans Leidekker598c5422010-02-16 11:44:47 +01002918 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2919 comp->ActionRequest == INSTALLSTATE_SOURCE)
Mike McCormackfe8cd382006-03-09 14:21:37 +09002920 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002921 if (!comp->FullKeypath)
2922 continue;
2923
James Hawkins288af812008-06-18 00:51:13 -05002924 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
James Hawkinsb198f4f2008-12-09 00:21:00 -06002925 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2926 &hkey, TRUE);
James Hawkins288af812008-06-18 00:51:13 -05002927 else
James Hawkinsb198f4f2008-12-09 00:21:00 -06002928 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2929 &hkey, TRUE);
James Hawkins288af812008-06-18 00:51:13 -05002930
James Hawkins4aa3a992008-06-18 00:49:42 -05002931 if (rc != ERROR_SUCCESS)
2932 continue;
Mike McCormackfe8cd382006-03-09 14:21:37 +09002933
2934 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartfa384f62004-12-22 18:46:17 +00002935 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002936 static const WCHAR szPermKey[] =
2937 { '0','0','0','0','0','0','0','0','0','0','0','0',
2938 '0','0','0','0','0','0','0','0','0','0','0','0',
2939 '0','0','0','0','0','0','0','0',0 };
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002940
James Hawkins4aa3a992008-06-18 00:49:42 -05002941 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002942 }
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002943
James Hawkins96dd6ce2008-08-21 02:14:26 -05002944 if (comp->Action == INSTALLSTATE_LOCAL)
2945 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2946 else
2947 {
2948 MSIFILE *file;
2949 MSIRECORD *row;
2950 LPWSTR ptr, ptr2;
2951 WCHAR source[MAX_PATH];
2952 WCHAR base[MAX_PATH];
James Hawkinsd15fddf2008-10-06 22:26:20 -05002953 LPWSTR sourcepath;
James Hawkins96dd6ce2008-08-21 02:14:26 -05002954
2955 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2956 static const WCHAR query[] = {
2957 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2958 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2959 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2960 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2961 '`','D','i','s','k','I','d','`',0};
2962
2963 file = get_loaded_file(package, comp->KeyPath);
2964 if (!file)
2965 continue;
2966
2967 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2968 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2969 ptr2 = strrchrW(source, '\\') + 1;
2970 msiobj_release(&row->hdr);
2971
2972 lstrcpyW(base, package->PackagePath);
2973 ptr = strrchrW(base, '\\');
2974 *(ptr + 1) = '\0';
2975
James Hawkinsd15fddf2008-10-06 22:26:20 -05002976 sourcepath = resolve_file_source(package, file);
2977 ptr = sourcepath + lstrlenW(base);
James Hawkins96dd6ce2008-08-21 02:14:26 -05002978 lstrcpyW(ptr2, ptr);
James Hawkinsd15fddf2008-10-06 22:26:20 -05002979 msi_free(sourcepath);
James Hawkins96dd6ce2008-08-21 02:14:26 -05002980
2981 msi_reg_set_val_str(hkey, squished_pc, source);
2982 }
James Hawkins4aa3a992008-06-18 00:49:42 -05002983 RegCloseKey(hkey);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002984 }
Hans Leidekker598c5422010-02-16 11:44:47 +01002985 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
James Hawkins288af812008-06-18 00:51:13 -05002986 {
2987 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
James Hawkinsa9e02902008-12-09 00:21:19 -06002988 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
James Hawkins288af812008-06-18 00:51:13 -05002989 else
James Hawkinsa9e02902008-12-09 00:21:19 -06002990 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
James Hawkins288af812008-06-18 00:51:13 -05002991 }
Hans Leidekker27e90272010-03-23 11:46:24 +01002992 comp->Action = comp->ActionRequest;
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002993
2994 /* UI stuff */
2995 uirow = MSI_CreateRecord(3);
2996 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2997 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2998 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2999 ui_actiondata(package,szProcessComponents,uirow);
3000 msiobj_release( &uirow->hdr );
3001 }
James Hawkins4aa3a992008-06-18 00:49:42 -05003002
3003 return ERROR_SUCCESS;
Aric Stewartb942e182004-07-06 18:50:02 +00003004}
3005
Aric Stewart6e821732005-03-30 10:19:08 +00003006typedef struct {
3007 CLSID clsid;
3008 LPWSTR source;
3009
3010 LPWSTR path;
3011 ITypeLib *ptLib;
3012} typelib_struct;
3013
Mike McCormackf9acfe62005-06-07 20:29:51 +00003014static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
Aric Stewart6e821732005-03-30 10:19:08 +00003015 LPWSTR lpszName, LONG_PTR lParam)
3016{
3017 TLIBATTR *attr;
3018 typelib_struct *tl_struct = (typelib_struct*) lParam;
3019 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3020 int sz;
3021 HRESULT res;
3022
3023 if (!IS_INTRESOURCE(lpszName))
3024 {
3025 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3026 return TRUE;
3027 }
3028
3029 sz = strlenW(tl_struct->source)+4;
3030 sz *= sizeof(WCHAR);
3031
Mike McCormack2acf8002006-05-25 11:41:39 +09003032 if ((INT_PTR)lpszName == 1)
Aric Stewartca8c4e42005-06-02 15:13:57 +00003033 tl_struct->path = strdupW(tl_struct->source);
3034 else
3035 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003036 tl_struct->path = msi_alloc(sz);
Aric Stewartca8c4e42005-06-02 15:13:57 +00003037 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3038 }
Aric Stewart6e821732005-03-30 10:19:08 +00003039
3040 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3041 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
Michael Stefaniuc704ebf22008-10-08 01:33:34 +02003042 if (FAILED(res))
Aric Stewart6e821732005-03-30 10:19:08 +00003043 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003044 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003045 tl_struct->path = NULL;
3046
3047 return TRUE;
3048 }
3049
3050 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3051 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3052 {
3053 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3054 return FALSE;
3055 }
3056
Mike McCormackee034ba2005-09-20 11:59:14 +00003057 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003058 tl_struct->path = NULL;
3059
3060 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3061 ITypeLib_Release(tl_struct->ptLib);
3062
3063 return TRUE;
3064}
3065
Aric Stewart234dc4b2005-06-22 18:27:34 +00003066static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3067{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003068 MSIPACKAGE* package = param;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003069 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00003070 MSICOMPONENT *comp;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003071 MSIFILE *file;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003072 typelib_struct tl_struct;
James Hawkins469e4a52008-07-28 22:19:47 -05003073 ITypeLib *tlib;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003074 HMODULE module;
James Hawkins469e4a52008-07-28 22:19:47 -05003075 HRESULT hr;
3076
Aric Stewart234dc4b2005-06-22 18:27:34 +00003077 component = MSI_RecordGetString(row,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00003078 comp = get_loaded_component(package,component);
3079 if (!comp)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003080 return ERROR_SUCCESS;
3081
Hans Leidekker598c5422010-02-16 11:44:47 +01003082 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003083 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003084 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003085 comp->Action = comp->Installed;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003086 return ERROR_SUCCESS;
3087 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003088 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003089
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003090 file = get_loaded_file( package, comp->KeyPath );
3091 if (!file)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003092 return ERROR_SUCCESS;
3093
Hans Leidekker54391a12010-02-16 11:44:34 +01003094 ui_actiondata( package, szRegisterTypeLibraries, row );
3095
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003096 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
Mike McCormack51c66182005-10-27 12:36:12 +00003097 if (module)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003098 {
Mike McCormack51c66182005-10-27 12:36:12 +00003099 LPCWSTR guid;
3100 guid = MSI_RecordGetString(row,1);
3101 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003102 tl_struct.source = strdupW( file->TargetPath );
Aric Stewart234dc4b2005-06-22 18:27:34 +00003103 tl_struct.path = NULL;
3104
3105 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3106 (LONG_PTR)&tl_struct);
3107
Mike McCormack51c66182005-10-27 12:36:12 +00003108 if (tl_struct.path)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003109 {
3110 LPWSTR help = NULL;
3111 LPCWSTR helpid;
3112 HRESULT res;
3113
3114 helpid = MSI_RecordGetString(row,6);
3115
3116 if (helpid)
James Hawkins8cedb212007-03-29 02:38:57 -05003117 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003118 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
Mike McCormackee034ba2005-09-20 11:59:14 +00003119 msi_free(help);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003120
Michael Stefaniuc704ebf22008-10-08 01:33:34 +02003121 if (FAILED(res))
Aric Stewart234dc4b2005-06-22 18:27:34 +00003122 ERR("Failed to register type library %s\n",
3123 debugstr_w(tl_struct.path));
3124 else
Aric Stewart234dc4b2005-06-22 18:27:34 +00003125 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
Aric Stewart234dc4b2005-06-22 18:27:34 +00003126
3127 ITypeLib_Release(tl_struct.ptLib);
Mike McCormackee034ba2005-09-20 11:59:14 +00003128 msi_free(tl_struct.path);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003129 }
3130 else
3131 ERR("Failed to load type library %s\n",
3132 debugstr_w(tl_struct.source));
3133
3134 FreeLibrary(module);
Mike McCormackee034ba2005-09-20 11:59:14 +00003135 msi_free(tl_struct.source);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003136 }
3137 else
James Hawkins469e4a52008-07-28 22:19:47 -05003138 {
3139 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3140 if (FAILED(hr))
3141 {
3142 ERR("Failed to load type library: %08x\n", hr);
Hans Leidekker82d50fa2010-02-12 10:33:00 +01003143 return ERROR_INSTALL_FAILURE;
James Hawkins469e4a52008-07-28 22:19:47 -05003144 }
3145
3146 ITypeLib_Release(tlib);
3147 }
Aric Stewart234dc4b2005-06-22 18:27:34 +00003148
3149 return ERROR_SUCCESS;
3150}
3151
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003152static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
Aric Stewartfcb20c52004-07-06 18:51:16 +00003153{
3154 /*
Mike McCormackc90c7812004-07-09 22:58:27 +00003155 * OK this is a bit confusing.. I am given a _Component key and I believe
Aric Stewartfcb20c52004-07-06 18:51:16 +00003156 * that the file that is being registered as a type library is the "key file
Mike McCormackc90c7812004-07-09 22:58:27 +00003157 * of that component" which I interpret to mean "The file in the KeyPath of
3158 * that component".
Aric Stewartfcb20c52004-07-06 18:51:16 +00003159 */
3160 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003161 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003162 static const WCHAR Query[] =
3163 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003164 '`','T','y','p','e','L','i','b','`',0};
Aric Stewartfcb20c52004-07-06 18:51:16 +00003165
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003166 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003167 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00003168 return ERROR_SUCCESS;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003169
Aric Stewart234dc4b2005-06-22 18:27:34 +00003170 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003171 msiobj_release(&view->hdr);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003172 return rc;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003173}
3174
Hans Leidekker98761032010-02-12 10:32:35 +01003175static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3176{
3177 MSIPACKAGE *package = param;
3178 LPCWSTR component, guid;
3179 MSICOMPONENT *comp;
3180 GUID libid;
3181 UINT version;
3182 LCID language;
3183 SYSKIND syskind;
3184 HRESULT hr;
3185
3186 component = MSI_RecordGetString( row, 3 );
3187 comp = get_loaded_component( package, component );
3188 if (!comp)
3189 return ERROR_SUCCESS;
3190
Hans Leidekker598c5422010-02-16 11:44:47 +01003191 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
Hans Leidekker98761032010-02-12 10:32:35 +01003192 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003193 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
Hans Leidekker98761032010-02-12 10:32:35 +01003194 comp->Action = comp->Installed;
3195 return ERROR_SUCCESS;
3196 }
3197 comp->Action = INSTALLSTATE_ABSENT;
3198
Hans Leidekker54391a12010-02-16 11:44:34 +01003199 ui_actiondata( package, szUnregisterTypeLibraries, row );
3200
Hans Leidekker98761032010-02-12 10:32:35 +01003201 guid = MSI_RecordGetString( row, 1 );
3202 CLSIDFromString( (LPWSTR)guid, &libid );
3203 version = MSI_RecordGetInteger( row, 4 );
3204 language = MSI_RecordGetInteger( row, 2 );
3205
3206#ifdef _WIN64
3207 syskind = SYS_WIN64;
3208#else
3209 syskind = SYS_WIN32;
3210#endif
3211
3212 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3213 if (FAILED(hr))
3214 {
3215 WARN("Failed to unregister typelib: %08x\n", hr);
3216 }
3217
3218 return ERROR_SUCCESS;
3219}
3220
3221static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3222{
3223 UINT rc;
3224 MSIQUERY *view;
3225 static const WCHAR query[] =
3226 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3227 '`','T','y','p','e','L','i','b','`',0};
3228
3229 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3230 if (rc != ERROR_SUCCESS)
3231 return ERROR_SUCCESS;
3232
3233 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3234 msiobj_release( &view->hdr );
3235 return rc;
3236}
3237
Hans Leidekker2276c292010-02-15 10:20:01 +01003238static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3239{
3240 static const WCHAR szlnk[] = {'.','l','n','k',0};
3241 LPCWSTR directory, extension;
3242 LPWSTR link_folder, link_file, filename;
3243
3244 directory = MSI_RecordGetString( row, 2 );
3245 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3246
3247 /* may be needed because of a bug somewhere else */
3248 create_full_pathW( link_folder );
3249
3250 filename = msi_dup_record_field( row, 3 );
3251 reduce_to_longfilename( filename );
3252
3253 extension = strchrW( filename, '.' );
3254 if (!extension || strcmpiW( extension, szlnk ))
3255 {
3256 int len = strlenW( filename );
3257 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3258 memcpy( filename + len, szlnk, sizeof(szlnk) );
3259 }
3260 link_file = build_directory_name( 2, link_folder, filename );
3261 msi_free( link_folder );
3262 msi_free( filename );
3263
3264 return link_file;
3265}
3266
Aric Stewart9adacf62005-06-24 11:58:21 +00003267static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003268{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003269 MSIPACKAGE *package = param;
Hans Leidekker2276c292010-02-15 10:20:01 +01003270 LPWSTR link_file, deformated, path;
3271 LPCWSTR component, target;
Mike McCormack38d67a42005-08-22 09:15:23 +00003272 MSICOMPONENT *comp;
Mike McCormack20c57462006-05-24 17:41:04 +09003273 IShellLinkW *sl = NULL;
3274 IPersistFile *pf = NULL;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003275 HRESULT res;
3276
Hans Leidekker2276c292010-02-15 10:20:01 +01003277 component = MSI_RecordGetString(row, 4);
3278 comp = get_loaded_component(package, component);
Mike McCormack38d67a42005-08-22 09:15:23 +00003279 if (!comp)
Aric Stewart9adacf62005-06-24 11:58:21 +00003280 return ERROR_SUCCESS;
3281
Hans Leidekker598c5422010-02-16 11:44:47 +01003282 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart9adacf62005-06-24 11:58:21 +00003283 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003284 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003285 comp->Action = comp->Installed;
Aric Stewart9adacf62005-06-24 11:58:21 +00003286 return ERROR_SUCCESS;
3287 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003288 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart9adacf62005-06-24 11:58:21 +00003289
3290 ui_actiondata(package,szCreateShortcuts,row);
3291
3292 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3293 &IID_IShellLinkW, (LPVOID *) &sl );
3294
Mike McCormack20c57462006-05-24 17:41:04 +09003295 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003296 {
Mike McCormack20c57462006-05-24 17:41:04 +09003297 ERR("CLSID_ShellLink not available\n");
3298 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003299 }
3300
3301 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
Mike McCormack20c57462006-05-24 17:41:04 +09003302 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003303 {
Mike McCormack20c57462006-05-24 17:41:04 +09003304 ERR("QueryInterface(IID_IPersistFile) failed\n");
3305 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003306 }
3307
Hans Leidekker2276c292010-02-15 10:20:01 +01003308 target = MSI_RecordGetString(row, 5);
3309 if (strchrW(target, '['))
Robert Shearman4ac85672006-02-22 16:31:00 +00003310 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003311 deformat_string(package, target, &deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003312 IShellLinkW_SetPath(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003313 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003314 }
3315 else
3316 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003317 FIXME("poorly handled shortcut format, advertised shortcut\n");
Mike McCormack566c69e2005-09-22 10:49:17 +00003318 IShellLinkW_SetPath(sl,comp->FullKeypath);
Aric Stewart9adacf62005-06-24 11:58:21 +00003319 }
3320
3321 if (!MSI_RecordIsNull(row,6))
3322 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003323 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3324 deformat_string(package, arguments, &deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003325 IShellLinkW_SetArguments(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003326 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003327 }
3328
3329 if (!MSI_RecordIsNull(row,7))
3330 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003331 LPCWSTR description = MSI_RecordGetString(row, 7);
3332 IShellLinkW_SetDescription(sl, description);
Aric Stewart9adacf62005-06-24 11:58:21 +00003333 }
3334
3335 if (!MSI_RecordIsNull(row,8))
3336 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3337
3338 if (!MSI_RecordIsNull(row,9))
3339 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003340 INT index;
Hans Leidekker2276c292010-02-15 10:20:01 +01003341 LPCWSTR icon = MSI_RecordGetString(row, 9);
Aric Stewart9adacf62005-06-24 11:58:21 +00003342
Hans Leidekker2276c292010-02-15 10:20:01 +01003343 path = build_icon_path(package, icon);
Aric Stewart9adacf62005-06-24 11:58:21 +00003344 index = MSI_RecordGetInteger(row,10);
3345
Robert Shearmanab378802006-08-03 20:24:10 +01003346 /* no value means 0 */
3347 if (index == MSI_NULL_INTEGER)
3348 index = 0;
3349
Hans Leidekker2276c292010-02-15 10:20:01 +01003350 IShellLinkW_SetIconLocation(sl, path, index);
3351 msi_free(path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003352 }
3353
3354 if (!MSI_RecordIsNull(row,11))
3355 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3356
3357 if (!MSI_RecordIsNull(row,12))
3358 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003359 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3360 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3361 if (path)
3362 IShellLinkW_SetWorkingDirectory(sl, path);
3363 msi_free(path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003364 }
3365
Hans Leidekker2276c292010-02-15 10:20:01 +01003366 link_file = get_link_file(package, row);
Aric Stewart9adacf62005-06-24 11:58:21 +00003367
Hans Leidekker2276c292010-02-15 10:20:01 +01003368 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3369 IPersistFile_Save(pf, link_file, FALSE);
3370
3371 msi_free(link_file);
Aric Stewart9adacf62005-06-24 11:58:21 +00003372
Mike McCormack20c57462006-05-24 17:41:04 +09003373err:
3374 if (pf)
3375 IPersistFile_Release( pf );
3376 if (sl)
3377 IShellLinkW_Release( sl );
Aric Stewart9adacf62005-06-24 11:58:21 +00003378
3379 return ERROR_SUCCESS;
3380}
3381
3382static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3383{
3384 UINT rc;
3385 HRESULT res;
3386 MSIQUERY * view;
3387 static const WCHAR Query[] =
3388 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3389 '`','S','h','o','r','t','c','u','t','`',0};
3390
Aric Stewart9adacf62005-06-24 11:58:21 +00003391 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3392 if (rc != ERROR_SUCCESS)
3393 return ERROR_SUCCESS;
3394
Aric Stewart2cf222f2004-07-06 19:00:23 +00003395 res = CoInitialize( NULL );
Aric Stewart2cf222f2004-07-06 19:00:23 +00003396
Aric Stewart9adacf62005-06-24 11:58:21 +00003397 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003398 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003399
Hans Leidekkerdd1ca6c2009-09-10 10:10:33 +02003400 if (SUCCEEDED(res))
3401 CoUninitialize();
Aric Stewart2cf222f2004-07-06 19:00:23 +00003402
3403 return rc;
3404}
3405
Hans Leidekker2276c292010-02-15 10:20:01 +01003406static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3407{
3408 MSIPACKAGE *package = param;
3409 LPWSTR link_file;
3410 LPCWSTR component;
3411 MSICOMPONENT *comp;
3412
3413 component = MSI_RecordGetString( row, 4 );
3414 comp = get_loaded_component( package, component );
3415 if (!comp)
3416 return ERROR_SUCCESS;
3417
Hans Leidekker598c5422010-02-16 11:44:47 +01003418 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
Hans Leidekker2276c292010-02-15 10:20:01 +01003419 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003420 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
Hans Leidekker2276c292010-02-15 10:20:01 +01003421 comp->Action = comp->Installed;
3422 return ERROR_SUCCESS;
3423 }
3424 comp->Action = INSTALLSTATE_ABSENT;
3425
3426 ui_actiondata( package, szRemoveShortcuts, row );
3427
3428 link_file = get_link_file( package, row );
3429
3430 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3431 if (!DeleteFileW( link_file ))
3432 {
3433 WARN("Failed to remove shortcut file %u\n", GetLastError());
3434 }
3435 msi_free( link_file );
3436
3437 return ERROR_SUCCESS;
3438}
3439
3440static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3441{
3442 UINT rc;
3443 MSIQUERY *view;
3444 static const WCHAR query[] =
3445 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3446 '`','S','h','o','r','t','c','u','t','`',0};
3447
3448 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3449 if (rc != ERROR_SUCCESS)
3450 return ERROR_SUCCESS;
3451
3452 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3453 msiobj_release( &view->hdr );
3454
3455 return rc;
3456}
3457
James Hawkinsfac97bb2008-06-23 22:56:56 -05003458static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
Aric Stewart916ef942005-06-22 18:42:19 +00003459{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003460 MSIPACKAGE* package = param;
Aric Stewart916ef942005-06-22 18:42:19 +00003461 HANDLE the_file;
Mike McCormack75658d72005-09-22 10:33:57 +00003462 LPWSTR FilePath;
3463 LPCWSTR FileName;
Aric Stewart916ef942005-06-22 18:42:19 +00003464 CHAR buffer[1024];
3465 DWORD sz;
3466 UINT rc;
3467
3468 FileName = MSI_RecordGetString(row,1);
3469 if (!FileName)
3470 {
3471 ERR("Unable to get FileName\n");
3472 return ERROR_SUCCESS;
3473 }
3474
Mike McCormack75658d72005-09-22 10:33:57 +00003475 FilePath = build_icon_path(package,FileName);
Aric Stewart916ef942005-06-22 18:42:19 +00003476
3477 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3478
3479 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3480 FILE_ATTRIBUTE_NORMAL, NULL);
3481
3482 if (the_file == INVALID_HANDLE_VALUE)
3483 {
3484 ERR("Unable to create file %s\n",debugstr_w(FilePath));
Mike McCormackee034ba2005-09-20 11:59:14 +00003485 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003486 return ERROR_SUCCESS;
3487 }
3488
3489 do
3490 {
3491 DWORD write;
3492 sz = 1024;
3493 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3494 if (rc != ERROR_SUCCESS)
3495 {
3496 ERR("Failed to get stream\n");
3497 CloseHandle(the_file);
3498 DeleteFileW(FilePath);
3499 break;
3500 }
3501 WriteFile(the_file,buffer,sz,&write,NULL);
3502 } while (sz == 1024);
3503
Mike McCormackee034ba2005-09-20 11:59:14 +00003504 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003505 CloseHandle(the_file);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003506
Aric Stewart916ef942005-06-22 18:42:19 +00003507 return ERROR_SUCCESS;
3508}
Aric Stewart2cf222f2004-07-06 19:00:23 +00003509
James Hawkinsfac97bb2008-06-23 22:56:56 -05003510static UINT msi_publish_icons(MSIPACKAGE *package)
3511{
3512 UINT r;
3513 MSIQUERY *view;
3514
3515 static const WCHAR query[]= {
3516 'S','E','L','E','C','T',' ','*',' ',
3517 'F','R','O','M',' ','`','I','c','o','n','`',0};
3518
3519 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3520 if (r == ERROR_SUCCESS)
3521 {
3522 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3523 msiobj_release(&view->hdr);
3524 }
3525
3526 return ERROR_SUCCESS;
3527}
3528
James Hawkins2d4e4b62008-06-23 23:05:25 -05003529static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
James Hawkins68e60712008-06-23 22:57:36 -05003530{
3531 UINT r;
James Hawkins2d4e4b62008-06-23 23:05:25 -05003532 HKEY source;
James Hawkins68e60712008-06-23 22:57:36 -05003533 LPWSTR buffer;
3534 MSIMEDIADISK *disk;
3535 MSISOURCELISTINFO *info;
3536
James Hawkins2d4e4b62008-06-23 23:05:25 -05003537 r = RegCreateKeyW(hkey, szSourceList, &source);
3538 if (r != ERROR_SUCCESS)
3539 return r;
3540
3541 RegCloseKey(source);
James Hawkins68e60712008-06-23 22:57:36 -05003542
3543 buffer = strrchrW(package->PackagePath, '\\') + 1;
3544 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3545 package->Context, MSICODE_PRODUCT,
3546 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3547 if (r != ERROR_SUCCESS)
3548 return r;
3549
3550 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3551 package->Context, MSICODE_PRODUCT,
3552 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3553 if (r != ERROR_SUCCESS)
3554 return r;
3555
3556 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3557 package->Context, MSICODE_PRODUCT,
3558 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3559 if (r != ERROR_SUCCESS)
3560 return r;
3561
3562 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3563 {
3564 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3565 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3566 info->options, info->value);
3567 else
3568 MsiSourceListSetInfoW(package->ProductCode, NULL,
3569 info->context, info->options,
3570 info->property, info->value);
3571 }
3572
3573 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3574 {
3575 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3576 disk->context, disk->options,
3577 disk->disk_id, disk->volume_label, disk->disk_prompt);
3578 }
3579
3580 return ERROR_SUCCESS;
3581}
3582
James Hawkinsebeb5372008-06-23 22:59:41 -05003583static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3584{
3585 MSIHANDLE hdb, suminfo;
3586 WCHAR guids[MAX_PATH];
James Hawkinsdb2e8d22008-06-23 23:00:21 -05003587 WCHAR packcode[SQUISH_GUID_SIZE];
James Hawkinsebeb5372008-06-23 22:59:41 -05003588 LPWSTR buffer;
3589 LPWSTR ptr;
3590 DWORD langid;
3591 DWORD size;
3592 UINT r;
3593
3594 static const WCHAR szProductLanguage[] =
3595 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3596 static const WCHAR szARPProductIcon[] =
3597 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3598 static const WCHAR szProductVersion[] =
3599 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
James Hawkinsef640a62008-06-23 23:01:44 -05003600 static const WCHAR szAssignment[] =
3601 {'A','s','s','i','g','n','m','e','n','t',0};
3602 static const WCHAR szAdvertiseFlags[] =
3603 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3604 static const WCHAR szClients[] =
3605 {'C','l','i','e','n','t','s',0};
3606 static const WCHAR szColon[] = {':',0};
James Hawkinsebeb5372008-06-23 22:59:41 -05003607
3608 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3609 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3610 msi_free(buffer);
3611
3612 langid = msi_get_property_int(package, szProductLanguage, 0);
3613 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3614
James Hawkinsebeb5372008-06-23 22:59:41 -05003615 /* FIXME */
3616 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3617
3618 buffer = msi_dup_property(package, szARPProductIcon);
3619 if (buffer)
3620 {
3621 LPWSTR path = build_icon_path(package,buffer);
3622 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3623 msi_free(path);
3624 msi_free(buffer);
3625 }
3626
3627 buffer = msi_dup_property(package, szProductVersion);
3628 if (buffer)
3629 {
3630 DWORD verdword = msi_version_str_to_dword(buffer);
3631 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3632 msi_free(buffer);
3633 }
3634
James Hawkinsef640a62008-06-23 23:01:44 -05003635 msi_reg_set_val_dword(hkey, szAssignment, 0);
3636 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3637 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3638 msi_reg_set_val_str(hkey, szClients, szColon);
3639
James Hawkinsebeb5372008-06-23 22:59:41 -05003640 hdb = alloc_msihandle(&package->db->hdr);
3641 if (!hdb)
3642 return ERROR_NOT_ENOUGH_MEMORY;
3643
3644 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3645 MsiCloseHandle(hdb);
3646 if (r != ERROR_SUCCESS)
3647 goto done;
3648
3649 size = MAX_PATH;
3650 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3651 NULL, guids, &size);
3652 if (r != ERROR_SUCCESS)
3653 goto done;
3654
3655 ptr = strchrW(guids, ';');
3656 if (ptr) *ptr = 0;
James Hawkinsdb2e8d22008-06-23 23:00:21 -05003657 squash_guid(guids, packcode);
3658 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
James Hawkinsebeb5372008-06-23 22:59:41 -05003659
3660done:
3661 MsiCloseHandle(suminfo);
3662 return ERROR_SUCCESS;
3663}
3664
James Hawkinscdb33f82008-06-23 23:02:54 -05003665static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3666{
3667 UINT r;
3668 HKEY hkey;
3669 LPWSTR upgrade;
3670 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3671
3672 static const WCHAR szUpgradeCode[] =
3673 {'U','p','g','r','a','d','e','C','o','d','e',0};
3674
3675 upgrade = msi_dup_property(package, szUpgradeCode);
3676 if (!upgrade)
3677 return ERROR_SUCCESS;
3678
James Hawkins58e15432008-06-23 23:04:46 -05003679 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3680 {
3681 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3682 if (r != ERROR_SUCCESS)
3683 goto done;
3684 }
3685 else
3686 {
3687 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3688 if (r != ERROR_SUCCESS)
3689 goto done;
3690 }
James Hawkinscdb33f82008-06-23 23:02:54 -05003691
3692 squash_guid(package->ProductCode, squashed_pc);
3693 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3694
3695 RegCloseKey(hkey);
3696
3697done:
3698 msi_free(upgrade);
3699 return r;
3700}
3701
James Hawkinsa2df31a2007-07-02 20:21:26 -07003702static BOOL msi_check_publish(MSIPACKAGE *package)
3703{
3704 MSIFEATURE *feature;
3705
3706 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3707 {
3708 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3709 return TRUE;
3710 }
3711
3712 return FALSE;
3713}
3714
James Hawkinscdb33f82008-06-23 23:02:54 -05003715static BOOL msi_check_unpublish(MSIPACKAGE *package)
3716{
3717 MSIFEATURE *feature;
3718
3719 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3720 {
3721 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3722 return FALSE;
3723 }
3724
3725 return TRUE;
3726}
3727
James Hawkins01eb9302008-12-14 21:07:23 -06003728static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3729{
3730 WCHAR patch_squashed[GUID_SIZE];
3731 HKEY patches;
3732 LONG res;
3733 UINT r = ERROR_FUNCTION_FAILED;
3734
James Hawkins01eb9302008-12-14 21:07:23 -06003735 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3736 &patches, NULL);
3737 if (res != ERROR_SUCCESS)
3738 return ERROR_FUNCTION_FAILED;
3739
3740 squash_guid(package->patch->patchcode, patch_squashed);
3741
3742 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3743 (const BYTE *)patch_squashed,
3744 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3745 if (res != ERROR_SUCCESS)
3746 goto done;
3747
3748 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3749 (const BYTE *)package->patch->transforms,
3750 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3751 if (res == ERROR_SUCCESS)
3752 r = ERROR_SUCCESS;
3753
3754done:
3755 RegCloseKey(patches);
3756 return r;
3757}
3758
Aric Stewart2cf222f2004-07-06 19:00:23 +00003759/*
3760 * 99% of the work done here is only done for
3761 * advertised installs. However this is where the
3762 * Icon table is processed and written out
Francois Gouget817c5202004-07-16 19:15:40 +00003763 * so that is what I am going to do here.
Aric Stewart2cf222f2004-07-06 19:00:23 +00003764 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003765static UINT ACTION_PublishProduct(MSIPACKAGE *package)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003766{
3767 UINT rc;
Hans Leidekkerc547fb32010-03-05 12:27:49 +01003768 HKEY hukey = NULL, hudkey = NULL;
3769 MSIRECORD *uirow;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003770
James Hawkinsa2df31a2007-07-02 20:21:26 -07003771 /* FIXME: also need to publish if the product is in advertise mode */
3772 if (!msi_check_publish(package))
3773 return ERROR_SUCCESS;
3774
James Hawkinsc965d832009-03-22 14:30:16 -07003775 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
James Hawkins70be1e72008-11-03 22:16:43 -06003776 &hukey, TRUE);
3777 if (rc != ERROR_SUCCESS)
3778 goto end;
3779
James Hawkins4a9f6992008-12-14 21:07:06 -06003780 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3781 NULL, &hudkey, TRUE);
3782 if (rc != ERROR_SUCCESS)
3783 goto end;
Aric Stewart6269f002005-01-17 13:40:39 +00003784
James Hawkinscdb33f82008-06-23 23:02:54 -05003785 rc = msi_publish_upgrade_code(package);
3786 if (rc != ERROR_SUCCESS)
3787 goto end;
James Hawkinsebeb5372008-06-23 22:59:41 -05003788
James Hawkins01eb9302008-12-14 21:07:23 -06003789 if (package->patch)
3790 {
3791 rc = msi_publish_patch(package, hukey, hudkey);
3792 if (rc != ERROR_SUCCESS)
3793 goto end;
3794 }
3795
James Hawkinsebeb5372008-06-23 22:59:41 -05003796 rc = msi_publish_product_properties(package, hukey);
3797 if (rc != ERROR_SUCCESS)
Dan Kegel337e1e22006-08-28 09:44:35 -07003798 goto end;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003799
James Hawkins2d4e4b62008-06-23 23:05:25 -05003800 rc = msi_publish_sourcelist(package, hukey);
James Hawkins68e60712008-06-23 22:57:36 -05003801 if (rc != ERROR_SUCCESS)
3802 goto end;
James Hawkins5e46fc92007-07-02 20:20:20 -07003803
James Hawkins68e60712008-06-23 22:57:36 -05003804 rc = msi_publish_icons(package);
James Hawkinsfac97bb2008-06-23 22:56:56 -05003805
Aric Stewart6269f002005-01-17 13:40:39 +00003806end:
Hans Leidekkerc547fb32010-03-05 12:27:49 +01003807 uirow = MSI_CreateRecord( 1 );
3808 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3809 ui_actiondata( package, szPublishProduct, uirow );
3810 msiobj_release( &uirow->hdr );
3811
Aric Stewart6269f002005-01-17 13:40:39 +00003812 RegCloseKey(hukey);
James Hawkinsc18b7752007-06-26 19:22:46 -07003813 RegCloseKey(hudkey);
Aric Stewart6269f002005-01-17 13:40:39 +00003814
Aric Stewart2cf222f2004-07-06 19:00:23 +00003815 return rc;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003816}
3817
Hans Leidekkerb891d082010-03-02 14:58:55 +01003818static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3819{
3820 WCHAR *filename, *ptr, *folder, *ret;
3821 const WCHAR *dirprop;
3822
3823 filename = msi_dup_record_field( row, 2 );
3824 if (filename && (ptr = strchrW( filename, '|' )))
3825 ptr++;
3826 else
3827 ptr = filename;
3828
3829 dirprop = MSI_RecordGetString( row, 3 );
3830 if (dirprop)
3831 {
3832 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3833 if (!folder)
3834 folder = msi_dup_property( package, dirprop );
3835 }
3836 else
3837 folder = msi_dup_property( package, szWindowsFolder );
3838
3839 if (!folder)
3840 {
3841 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3842 msi_free( filename );
3843 return NULL;
3844 }
3845
3846 ret = build_directory_name( 2, folder, ptr );
3847
3848 msi_free( filename );
3849 msi_free( folder );
3850 return ret;
3851}
3852
Aric Stewartaded32f2005-06-23 09:46:31 +00003853static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3854{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003855 MSIPACKAGE *package = param;
Hans Leidekkerb891d082010-03-02 14:58:55 +01003856 LPCWSTR component, section, key, value, identifier;
3857 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
Aric Stewartaded32f2005-06-23 09:46:31 +00003858 MSIRECORD * uirow;
Mike McCormack38d67a42005-08-22 09:15:23 +00003859 INT action;
3860 MSICOMPONENT *comp;
Aric Stewartaded32f2005-06-23 09:46:31 +00003861
3862 component = MSI_RecordGetString(row, 8);
Mike McCormack38d67a42005-08-22 09:15:23 +00003863 comp = get_loaded_component(package,component);
Hans Leidekker598c5422010-02-16 11:44:47 +01003864 if (!comp)
3865 return ERROR_SUCCESS;
Aric Stewartaded32f2005-06-23 09:46:31 +00003866
Hans Leidekker598c5422010-02-16 11:44:47 +01003867 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewartaded32f2005-06-23 09:46:31 +00003868 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003869 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003870 comp->Action = comp->Installed;
Aric Stewartaded32f2005-06-23 09:46:31 +00003871 return ERROR_SUCCESS;
3872 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003873 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewartaded32f2005-06-23 09:46:31 +00003874
3875 identifier = MSI_RecordGetString(row,1);
Aric Stewartaded32f2005-06-23 09:46:31 +00003876 section = MSI_RecordGetString(row,4);
3877 key = MSI_RecordGetString(row,5);
3878 value = MSI_RecordGetString(row,6);
3879 action = MSI_RecordGetInteger(row,7);
3880
3881 deformat_string(package,section,&deformated_section);
3882 deformat_string(package,key,&deformated_key);
3883 deformat_string(package,value,&deformated_value);
3884
Hans Leidekkerb891d082010-03-02 14:58:55 +01003885 fullname = get_ini_file_name(package, row);
Aric Stewartaded32f2005-06-23 09:46:31 +00003886
3887 if (action == 0)
3888 {
3889 TRACE("Adding value %s to section %s in %s\n",
3890 debugstr_w(deformated_key), debugstr_w(deformated_section),
3891 debugstr_w(fullname));
3892 WritePrivateProfileStringW(deformated_section, deformated_key,
3893 deformated_value, fullname);
3894 }
3895 else if (action == 1)
3896 {
3897 WCHAR returned[10];
3898 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3899 returned, 10, fullname);
3900 if (returned[0] == 0)
3901 {
3902 TRACE("Adding value %s to section %s in %s\n",
3903 debugstr_w(deformated_key), debugstr_w(deformated_section),
3904 debugstr_w(fullname));
3905
3906 WritePrivateProfileStringW(deformated_section, deformated_key,
3907 deformated_value, fullname);
3908 }
3909 }
3910 else if (action == 3)
3911 FIXME("Append to existing section not yet implemented\n");
3912
3913 uirow = MSI_CreateRecord(4);
3914 MSI_RecordSetStringW(uirow,1,identifier);
3915 MSI_RecordSetStringW(uirow,2,deformated_section);
3916 MSI_RecordSetStringW(uirow,3,deformated_key);
3917 MSI_RecordSetStringW(uirow,4,deformated_value);
3918 ui_actiondata(package,szWriteIniValues,uirow);
3919 msiobj_release( &uirow->hdr );
James Hawkinsbf9538f2008-10-27 00:56:04 -05003920
Mike McCormackee034ba2005-09-20 11:59:14 +00003921 msi_free(fullname);
Mike McCormackee034ba2005-09-20 11:59:14 +00003922 msi_free(deformated_key);
3923 msi_free(deformated_value);
3924 msi_free(deformated_section);
Aric Stewartaded32f2005-06-23 09:46:31 +00003925 return ERROR_SUCCESS;
3926}
3927
Aric Stewart516a9c72005-01-14 15:59:26 +00003928static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3929{
3930 UINT rc;
3931 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003932 static const WCHAR ExecSeqQuery[] =
3933 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003934 '`','I','n','i','F','i','l','e','`',0};
Aric Stewart516a9c72005-01-14 15:59:26 +00003935
3936 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3937 if (rc != ERROR_SUCCESS)
3938 {
3939 TRACE("no IniFile table\n");
3940 return ERROR_SUCCESS;
3941 }
3942
Aric Stewartaded32f2005-06-23 09:46:31 +00003943 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
Aric Stewart516a9c72005-01-14 15:59:26 +00003944 msiobj_release(&view->hdr);
3945 return rc;
3946}
3947
Hans Leidekkerb891d082010-03-02 14:58:55 +01003948static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3949{
3950 MSIPACKAGE *package = param;
3951 LPCWSTR component, section, key, value, identifier;
3952 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3953 MSICOMPONENT *comp;
3954 MSIRECORD *uirow;
3955 INT action;
3956
3957 component = MSI_RecordGetString( row, 8 );
3958 comp = get_loaded_component( package, component );
3959 if (!comp)
3960 return ERROR_SUCCESS;
3961
3962 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3963 {
3964 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3965 comp->Action = comp->Installed;
3966 return ERROR_SUCCESS;
3967 }
3968 comp->Action = INSTALLSTATE_ABSENT;
3969
3970 identifier = MSI_RecordGetString( row, 1 );
3971 section = MSI_RecordGetString( row, 4 );
3972 key = MSI_RecordGetString( row, 5 );
3973 value = MSI_RecordGetString( row, 6 );
3974 action = MSI_RecordGetInteger( row, 7 );
3975
3976 deformat_string( package, section, &deformated_section );
3977 deformat_string( package, key, &deformated_key );
3978 deformat_string( package, value, &deformated_value );
3979
3980 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3981 {
3982 filename = get_ini_file_name( package, row );
3983
3984 TRACE("Removing key %s from section %s in %s\n",
3985 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3986
3987 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3988 {
3989 WARN("Unable to remove key %u\n", GetLastError());
3990 }
3991 msi_free( filename );
3992 }
3993 else
3994 FIXME("Unsupported action %d\n", action);
3995
3996
3997 uirow = MSI_CreateRecord( 4 );
3998 MSI_RecordSetStringW( uirow, 1, identifier );
3999 MSI_RecordSetStringW( uirow, 2, deformated_section );
4000 MSI_RecordSetStringW( uirow, 3, deformated_key );
4001 MSI_RecordSetStringW( uirow, 4, deformated_value );
4002 ui_actiondata( package, szRemoveIniValues, uirow );
4003 msiobj_release( &uirow->hdr );
4004
4005 msi_free( deformated_key );
4006 msi_free( deformated_value );
4007 msi_free( deformated_section );
4008 return ERROR_SUCCESS;
4009}
4010
4011static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4012{
4013 MSIPACKAGE *package = param;
4014 LPCWSTR component, section, key, value, identifier;
4015 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4016 MSICOMPONENT *comp;
4017 MSIRECORD *uirow;
4018 INT action;
4019
4020 component = MSI_RecordGetString( row, 8 );
4021 comp = get_loaded_component( package, component );
4022 if (!comp)
4023 return ERROR_SUCCESS;
4024
4025 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4026 {
4027 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4028 comp->Action = comp->Installed;
4029 return ERROR_SUCCESS;
4030 }
4031 comp->Action = INSTALLSTATE_LOCAL;
4032
4033 identifier = MSI_RecordGetString( row, 1 );
4034 section = MSI_RecordGetString( row, 4 );
4035 key = MSI_RecordGetString( row, 5 );
4036 value = MSI_RecordGetString( row, 6 );
4037 action = MSI_RecordGetInteger( row, 7 );
4038
4039 deformat_string( package, section, &deformated_section );
4040 deformat_string( package, key, &deformated_key );
4041 deformat_string( package, value, &deformated_value );
4042
4043 if (action == msidbIniFileActionRemoveLine)
4044 {
4045 filename = get_ini_file_name( package, row );
4046
4047 TRACE("Removing key %s from section %s in %s\n",
4048 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4049
4050 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4051 {
4052 WARN("Unable to remove key %u\n", GetLastError());
4053 }
4054 msi_free( filename );
4055 }
4056 else
4057 FIXME("Unsupported action %d\n", action);
4058
4059 uirow = MSI_CreateRecord( 4 );
4060 MSI_RecordSetStringW( uirow, 1, identifier );
4061 MSI_RecordSetStringW( uirow, 2, deformated_section );
4062 MSI_RecordSetStringW( uirow, 3, deformated_key );
4063 MSI_RecordSetStringW( uirow, 4, deformated_value );
4064 ui_actiondata( package, szRemoveIniValues, uirow );
4065 msiobj_release( &uirow->hdr );
4066
4067 msi_free( deformated_key );
4068 msi_free( deformated_value );
4069 msi_free( deformated_section );
4070 return ERROR_SUCCESS;
4071}
4072
4073static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4074{
4075 UINT rc;
4076 MSIQUERY *view;
4077 static const WCHAR query[] =
4078 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4079 '`','I','n','i','F','i','l','e','`',0};
4080 static const WCHAR remove_query[] =
4081 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4082 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4083
4084 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4085 if (rc == ERROR_SUCCESS)
4086 {
4087 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4088 msiobj_release( &view->hdr );
4089 if (rc != ERROR_SUCCESS)
4090 return rc;
4091 }
4092
4093 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4094 if (rc == ERROR_SUCCESS)
4095 {
4096 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4097 msiobj_release( &view->hdr );
4098 if (rc != ERROR_SUCCESS)
4099 return rc;
4100 }
4101
4102 return ERROR_SUCCESS;
4103}
4104
Aric Stewart854bfc42005-06-24 11:33:02 +00004105static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
Aric Stewart6269f002005-01-17 13:40:39 +00004106{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01004107 MSIPACKAGE *package = param;
Aric Stewart854bfc42005-06-24 11:33:02 +00004108 LPCWSTR filename;
4109 LPWSTR FullName;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004110 MSIFILE *file;
Aric Stewart854bfc42005-06-24 11:33:02 +00004111 DWORD len;
Aric Stewart8e233e92005-03-01 11:45:19 +00004112 static const WCHAR ExeStr[] =
Aric Stewartc5a14432005-05-18 17:46:12 +00004113 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4114 static const WCHAR close[] = {'\"',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004115 STARTUPINFOW si;
4116 PROCESS_INFORMATION info;
4117 BOOL brc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004118 MSIRECORD *uirow;
4119 LPWSTR uipath, p;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004120
4121 memset(&si,0,sizeof(STARTUPINFOW));
4122
Aric Stewart854bfc42005-06-24 11:33:02 +00004123 filename = MSI_RecordGetString(row,1);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004124 file = get_loaded_file( package, filename );
Aric Stewart854bfc42005-06-24 11:33:02 +00004125
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004126 if (!file)
Aric Stewart854bfc42005-06-24 11:33:02 +00004127 {
4128 ERR("Unable to find file id %s\n",debugstr_w(filename));
4129 return ERROR_SUCCESS;
4130 }
4131
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004132 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
Aric Stewart854bfc42005-06-24 11:33:02 +00004133
Mike McCormackee034ba2005-09-20 11:59:14 +00004134 FullName = msi_alloc(len*sizeof(WCHAR));
Aric Stewart854bfc42005-06-24 11:33:02 +00004135 strcpyW(FullName,ExeStr);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004136 strcatW( FullName, file->TargetPath );
Aric Stewart854bfc42005-06-24 11:33:02 +00004137 strcatW(FullName,close);
4138
4139 TRACE("Registering %s\n",debugstr_w(FullName));
4140 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4141 &si, &info);
4142
4143 if (brc)
Rob Shearmancda469c2008-08-17 18:29:11 +01004144 {
4145 CloseHandle(info.hThread);
Aric Stewart854bfc42005-06-24 11:33:02 +00004146 msi_dialog_check_messages(info.hProcess);
Rob Shearmancda469c2008-08-17 18:29:11 +01004147 CloseHandle(info.hProcess);
4148 }
Aric Stewart854bfc42005-06-24 11:33:02 +00004149
Robert Shearmand2e48e02006-01-23 17:29:50 +01004150 uirow = MSI_CreateRecord( 2 );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004151 MSI_RecordSetStringW( uirow, 1, filename );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004152 uipath = strdupW( file->TargetPath );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004153 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4154 MSI_RecordSetStringW( uirow, 2, uipath );
4155 ui_actiondata( package, szSelfRegModules, uirow );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004156 msiobj_release( &uirow->hdr );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004157
Hans Leidekkera4be9412010-03-23 11:45:33 +01004158 msi_free( FullName );
4159 msi_free( uipath );
Aric Stewart854bfc42005-06-24 11:33:02 +00004160 return ERROR_SUCCESS;
4161}
4162
4163static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4164{
4165 UINT rc;
4166 MSIQUERY * view;
4167 static const WCHAR ExecSeqQuery[] =
4168 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4169 '`','S','e','l','f','R','e','g','`',0};
4170
Aric Stewart6269f002005-01-17 13:40:39 +00004171 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4172 if (rc != ERROR_SUCCESS)
4173 {
4174 TRACE("no SelfReg table\n");
4175 return ERROR_SUCCESS;
4176 }
4177
Aric Stewart854bfc42005-06-24 11:33:02 +00004178 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
Aric Stewart6269f002005-01-17 13:40:39 +00004179 msiobj_release(&view->hdr);
Aric Stewart854bfc42005-06-24 11:33:02 +00004180
4181 return ERROR_SUCCESS;
Aric Stewart6269f002005-01-17 13:40:39 +00004182}
4183
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004184static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4185{
4186 static const WCHAR regsvr32[] =
4187 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4188 static const WCHAR close[] = {'\"',0};
4189 MSIPACKAGE *package = param;
4190 LPCWSTR filename;
4191 LPWSTR cmdline;
4192 MSIFILE *file;
4193 DWORD len;
4194 STARTUPINFOW si;
4195 PROCESS_INFORMATION pi;
4196 BOOL ret;
4197 MSIRECORD *uirow;
4198 LPWSTR uipath, p;
4199
4200 memset( &si, 0, sizeof(STARTUPINFOW) );
4201
4202 filename = MSI_RecordGetString( row, 1 );
4203 file = get_loaded_file( package, filename );
4204
4205 if (!file)
4206 {
4207 ERR("Unable to find file id %s\n", debugstr_w(filename));
4208 return ERROR_SUCCESS;
4209 }
4210
4211 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4212
4213 cmdline = msi_alloc( len * sizeof(WCHAR) );
4214 strcpyW( cmdline, regsvr32 );
4215 strcatW( cmdline, file->TargetPath );
4216 strcatW( cmdline, close );
4217
4218 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4219
4220 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4221 if (ret)
4222 {
4223 CloseHandle( pi.hThread );
4224 msi_dialog_check_messages( pi.hProcess );
4225 CloseHandle( pi.hProcess );
4226 }
4227
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004228 uirow = MSI_CreateRecord( 2 );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004229 MSI_RecordSetStringW( uirow, 1, filename );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004230 uipath = strdupW( file->TargetPath );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004231 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004232 MSI_RecordSetStringW( uirow, 2, uipath );
4233 ui_actiondata( package, szSelfUnregModules, uirow );
4234 msiobj_release( &uirow->hdr );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004235
Hans Leidekkera4be9412010-03-23 11:45:33 +01004236 msi_free( cmdline );
4237 msi_free( uipath );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004238 return ERROR_SUCCESS;
4239}
4240
4241static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4242{
4243 UINT rc;
4244 MSIQUERY *view;
4245 static const WCHAR query[] =
4246 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4247 '`','S','e','l','f','R','e','g','`',0};
4248
4249 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4250 if (rc != ERROR_SUCCESS)
4251 {
4252 TRACE("no SelfReg table\n");
4253 return ERROR_SUCCESS;
4254 }
4255
4256 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4257 msiobj_release( &view->hdr );
4258
4259 return ERROR_SUCCESS;
4260}
4261
Aric Stewart6269f002005-01-17 13:40:39 +00004262static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4263{
Mike McCormack1da28582005-08-22 14:09:17 +00004264 MSIFEATURE *feature;
Aric Stewart6269f002005-01-17 13:40:39 +00004265 UINT rc;
Hans Leidekker353035f2010-03-04 09:17:50 +01004266 HKEY hkey = NULL, userdata = NULL;
James Hawkins6ac08162007-08-09 11:38:48 -07004267
4268 if (!msi_check_publish(package))
4269 return ERROR_SUCCESS;
4270
James Hawkins0c01c582008-11-03 22:16:50 -06004271 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4272 &hkey, TRUE);
4273 if (rc != ERROR_SUCCESS)
4274 goto end;
4275
James Hawkinse3074342008-11-03 22:16:54 -06004276 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4277 &userdata, TRUE);
4278 if (rc != ERROR_SUCCESS)
4279 goto end;
James Hawkins9f11a5a2007-11-01 03:13:28 -05004280
Aric Stewart6269f002005-01-17 13:40:39 +00004281 /* here the guids are base 85 encoded */
Mike McCormack1da28582005-08-22 14:09:17 +00004282 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00004283 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004284 ComponentList *cl;
Aric Stewart6269f002005-01-17 13:40:39 +00004285 LPWSTR data = NULL;
4286 GUID clsid;
Aric Stewart6269f002005-01-17 13:40:39 +00004287 INT size;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004288 BOOL absent = FALSE;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004289 MSIRECORD *uirow;
Aric Stewart6269f002005-01-17 13:40:39 +00004290
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01004291 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4292 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4293 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004294
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004295 size = 1;
Mike McCormack1da28582005-08-22 14:09:17 +00004296 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004297 {
4298 size += 21;
4299 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00004300 if (feature->Feature_Parent)
Mike McCormack1da28582005-08-22 14:09:17 +00004301 size += strlenW( feature->Feature_Parent )+2;
Aric Stewart6269f002005-01-17 13:40:39 +00004302
Mike McCormackee034ba2005-09-20 11:59:14 +00004303 data = msi_alloc(size * sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00004304
4305 data[0] = 0;
Mike McCormack1da28582005-08-22 14:09:17 +00004306 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00004307 {
Mike McCormack38d67a42005-08-22 09:15:23 +00004308 MSICOMPONENT* component = cl->component;
Aric Stewart6269f002005-01-17 13:40:39 +00004309 WCHAR buf[21];
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004310
Mike McCormack3a940112006-04-19 02:29:03 +09004311 buf[0] = 0;
Mike McCormackefcc1ec2005-09-12 12:07:15 +00004312 if (component->ComponentId)
Aric Stewartc5a14432005-05-18 17:46:12 +00004313 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004314 TRACE("From %s\n",debugstr_w(component->ComponentId));
4315 CLSIDFromString(component->ComponentId, &clsid);
Aric Stewartc5a14432005-05-18 17:46:12 +00004316 encode_base85_guid(&clsid,buf);
4317 TRACE("to %s\n",debugstr_w(buf));
4318 strcatW(data,buf);
4319 }
Aric Stewart6269f002005-01-17 13:40:39 +00004320 }
James Hawkins9f11a5a2007-11-01 03:13:28 -05004321
Mike McCormack79ca56c2005-09-13 10:37:37 +00004322 if (feature->Feature_Parent)
Aric Stewart6269f002005-01-17 13:40:39 +00004323 {
4324 static const WCHAR sep[] = {'\2',0};
4325 strcatW(data,sep);
Mike McCormack1da28582005-08-22 14:09:17 +00004326 strcatW(data,feature->Feature_Parent);
Aric Stewart6269f002005-01-17 13:40:39 +00004327 }
4328
James Hawkins9f11a5a2007-11-01 03:13:28 -05004329 msi_reg_set_val_str( userdata, feature->Feature, data );
Mike McCormackee034ba2005-09-20 11:59:14 +00004330 msi_free(data);
Aric Stewart6269f002005-01-17 13:40:39 +00004331
Mike McCormack79ca56c2005-09-13 10:37:37 +00004332 size = 0;
4333 if (feature->Feature_Parent)
4334 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004335 if (!absent)
4336 {
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02004337 size += sizeof(WCHAR);
James Hawkins2a180e02008-06-19 00:32:59 -05004338 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
Hans Leidekker843382f2009-10-15 12:46:27 +02004339 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004340 }
4341 else
4342 {
Mike McCormack79ca56c2005-09-13 10:37:37 +00004343 size += 2*sizeof(WCHAR);
Mike McCormackee034ba2005-09-20 11:59:14 +00004344 data = msi_alloc(size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004345 data[0] = 0x6;
Mike McCormack79ca56c2005-09-13 10:37:37 +00004346 data[1] = 0;
4347 if (feature->Feature_Parent)
4348 strcpyW( &data[1], feature->Feature_Parent );
James Hawkins2a180e02008-06-19 00:32:59 -05004349 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
Mike McCormack16466af2005-07-06 10:33:30 +00004350 (LPBYTE)data,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00004351 msi_free(data);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004352 }
Robert Shearmand2e48e02006-01-23 17:29:50 +01004353
4354 /* the UI chunk */
4355 uirow = MSI_CreateRecord( 1 );
4356 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4357 ui_actiondata( package, szPublishFeatures, uirow);
4358 msiobj_release( &uirow->hdr );
4359 /* FIXME: call ui_progress? */
Aric Stewart6269f002005-01-17 13:40:39 +00004360 }
4361
Aric Stewart6269f002005-01-17 13:40:39 +00004362end:
James Hawkins2a180e02008-06-19 00:32:59 -05004363 RegCloseKey(hkey);
4364 RegCloseKey(userdata);
Aric Stewart6269f002005-01-17 13:40:39 +00004365 return rc;
4366}
4367
James Hawkins6ac08162007-08-09 11:38:48 -07004368static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4369{
4370 UINT r;
4371 HKEY hkey;
Hans Leidekker18a85ca2010-03-23 11:47:19 +01004372 MSIRECORD *uirow;
James Hawkins6ac08162007-08-09 11:38:48 -07004373
4374 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4375
James Hawkins0c01c582008-11-03 22:16:50 -06004376 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4377 &hkey, FALSE);
James Hawkins6ac08162007-08-09 11:38:48 -07004378 if (r == ERROR_SUCCESS)
4379 {
4380 RegDeleteValueW(hkey, feature->Feature);
4381 RegCloseKey(hkey);
4382 }
4383
James Hawkinse3074342008-11-03 22:16:54 -06004384 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4385 &hkey, FALSE);
James Hawkins6ac08162007-08-09 11:38:48 -07004386 if (r == ERROR_SUCCESS)
4387 {
4388 RegDeleteValueW(hkey, feature->Feature);
4389 RegCloseKey(hkey);
4390 }
4391
Hans Leidekker18a85ca2010-03-23 11:47:19 +01004392 uirow = MSI_CreateRecord( 1 );
4393 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4394 ui_actiondata( package, szUnpublishFeatures, uirow );
4395 msiobj_release( &uirow->hdr );
4396
James Hawkins6ac08162007-08-09 11:38:48 -07004397 return ERROR_SUCCESS;
4398}
4399
4400static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4401{
4402 MSIFEATURE *feature;
4403
James Hawkinsccdf5782007-11-01 03:14:18 -05004404 if (!msi_check_unpublish(package))
James Hawkins6ac08162007-08-09 11:38:48 -07004405 return ERROR_SUCCESS;
4406
4407 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4408 {
4409 msi_unpublish_feature(package, feature);
4410 }
4411
4412 return ERROR_SUCCESS;
4413}
4414
James Hawkins45de8962008-06-19 00:36:10 -05004415static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
Mike McCormackba293ee2005-10-27 12:08:16 +00004416{
4417 LPWSTR prop, val, key;
James Hawkins45de8962008-06-19 00:36:10 -05004418 SYSTEMTIME systime;
4419 DWORD size, langid;
4420 WCHAR date[9];
4421 LPWSTR buffer;
4422
4423 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4424 static const WCHAR szWindowsInstaller[] =
4425 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4426 static const WCHAR modpath_fmt[] =
4427 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4428 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4429 static const WCHAR szModifyPath[] =
4430 {'M','o','d','i','f','y','P','a','t','h',0};
4431 static const WCHAR szUninstallString[] =
4432 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4433 static const WCHAR szEstimatedSize[] =
4434 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4435 static const WCHAR szProductLanguage[] =
4436 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4437 static const WCHAR szProductVersion[] =
4438 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4439 static const WCHAR szProductName[] =
4440 {'P','r','o','d','u','c','t','N','a','m','e',0};
4441 static const WCHAR szDisplayName[] =
4442 {'D','i','s','p','l','a','y','N','a','m','e',0};
4443 static const WCHAR szDisplayVersion[] =
4444 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4445 static const WCHAR szManufacturer[] =
4446 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4447
Mike McCormackba293ee2005-10-27 12:08:16 +00004448 static const LPCSTR propval[] = {
4449 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4450 "ARPCONTACT", "Contact",
4451 "ARPCOMMENTS", "Comments",
4452 "ProductName", "DisplayName",
4453 "ProductVersion", "DisplayVersion",
4454 "ARPHELPLINK", "HelpLink",
4455 "ARPHELPTELEPHONE", "HelpTelephone",
4456 "ARPINSTALLLOCATION", "InstallLocation",
4457 "SourceDir", "InstallSource",
4458 "Manufacturer", "Publisher",
4459 "ARPREADME", "Readme",
4460 "ARPSIZE", "Size",
4461 "ARPURLINFOABOUT", "URLInfoAbout",
4462 "ARPURLUPDATEINFO", "URLUpdateInfo",
4463 NULL,
4464 };
4465 const LPCSTR *p = propval;
4466
James Hawkins45de8962008-06-19 00:36:10 -05004467 while (*p)
Mike McCormackba293ee2005-10-27 12:08:16 +00004468 {
James Hawkins45de8962008-06-19 00:36:10 -05004469 prop = strdupAtoW(*p++);
4470 key = strdupAtoW(*p++);
4471 val = msi_dup_property(package, prop);
4472 msi_reg_set_val_str(hkey, key, val);
Mike McCormackba293ee2005-10-27 12:08:16 +00004473 msi_free(val);
4474 msi_free(key);
4475 msi_free(prop);
4476 }
James Hawkins45de8962008-06-19 00:36:10 -05004477
4478 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4479
4480 size = deformat_string(package, modpath_fmt, &buffer);
4481 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4482 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4483 msi_free(buffer);
4484
4485 /* FIXME: Write real Estimated Size when we have it */
4486 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4487
4488 buffer = msi_dup_property(package, szProductName);
4489 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4490 msi_free(buffer);
4491
4492 buffer = msi_dup_property(package, cszSourceDir);
4493 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4494 msi_free(buffer);
4495
4496 buffer = msi_dup_property(package, szManufacturer);
4497 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4498 msi_free(buffer);
4499
4500 GetLocalTime(&systime);
4501 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4502 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4503
4504 langid = msi_get_property_int(package, szProductLanguage, 0);
4505 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4506
4507 buffer = msi_dup_property(package, szProductVersion);
4508 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4509 if (buffer)
4510 {
4511 DWORD verdword = msi_version_str_to_dword(buffer);
4512
4513 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4514 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4515 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4516 msi_free(buffer);
4517 }
4518
Mike McCormackba293ee2005-10-27 12:08:16 +00004519 return ERROR_SUCCESS;
4520}
4521
Aric Stewart2cae30b2005-01-19 19:07:40 +00004522static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4523{
James Hawkins45de8962008-06-19 00:36:10 -05004524 WCHAR squashed_pc[SQUISH_GUID_SIZE];
Hans Leidekker4341f182010-03-05 12:28:11 +01004525 MSIRECORD *uirow;
Aric Stewart36a01502005-06-08 19:07:52 +00004526 LPWSTR upgrade_code;
James Hawkins45de8962008-06-19 00:36:10 -05004527 HKEY hkey, props;
4528 HKEY upgrade;
4529 UINT rc;
4530
4531 static const WCHAR szUpgradeCode[] = {
4532 'U','p','g','r','a','d','e','C','o','d','e',0};
James Hawkins0e44e092007-07-02 20:21:58 -07004533
4534 /* FIXME: also need to publish if the product is in advertise mode */
4535 if (!msi_check_publish(package))
4536 return ERROR_SUCCESS;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004537
James Hawkins45de8962008-06-19 00:36:10 -05004538 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004539 if (rc != ERROR_SUCCESS)
Mike McCormackba293ee2005-10-27 12:08:16 +00004540 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004541
James Hawkinsb5e3e192008-12-14 21:07:14 -06004542 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4543 NULL, &props, TRUE);
4544 if (rc != ERROR_SUCCESS)
4545 goto done;
James Hawkinsd52f48f2008-03-06 16:12:40 -06004546
Hans Leidekker8dd3d382009-10-20 14:09:53 +02004547 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4548 msi_free( package->db->localfile );
4549 package->db->localfile = NULL;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004550
James Hawkins45de8962008-06-19 00:36:10 -05004551 rc = msi_publish_install_properties(package, hkey);
4552 if (rc != ERROR_SUCCESS)
4553 goto done;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004554
James Hawkins45de8962008-06-19 00:36:10 -05004555 rc = msi_publish_install_properties(package, props);
4556 if (rc != ERROR_SUCCESS)
4557 goto done;
Aric Stewart36a01502005-06-08 19:07:52 +00004558
James Hawkins45de8962008-06-19 00:36:10 -05004559 upgrade_code = msi_dup_property(package, szUpgradeCode);
Aric Stewart36a01502005-06-08 19:07:52 +00004560 if (upgrade_code)
4561 {
James Hawkins45de8962008-06-19 00:36:10 -05004562 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4563 squash_guid(package->ProductCode, squashed_pc);
4564 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4565 RegCloseKey(upgrade);
Mike McCormackee034ba2005-09-20 11:59:14 +00004566 msi_free(upgrade_code);
Aric Stewart36a01502005-06-08 19:07:52 +00004567 }
James Hawkinsbcba82d2008-04-05 06:02:04 -05004568
James Hawkins45de8962008-06-19 00:36:10 -05004569done:
Hans Leidekker4341f182010-03-05 12:28:11 +01004570 uirow = MSI_CreateRecord( 1 );
4571 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4572 ui_actiondata( package, szRegisterProduct, uirow );
4573 msiobj_release( &uirow->hdr );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004574
Hans Leidekker4341f182010-03-05 12:28:11 +01004575 RegCloseKey(hkey);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004576 return ERROR_SUCCESS;
4577}
4578
4579static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4580{
Mike McCormacka977b2c2005-11-03 09:56:29 +00004581 return execute_script(package,INSTALL_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004582}
4583
James Hawkins624bbbe2007-07-02 20:20:54 -07004584static UINT msi_unpublish_product(MSIPACKAGE *package)
4585{
James Hawkinscdb33f82008-06-23 23:02:54 -05004586 LPWSTR upgrade;
James Hawkins624bbbe2007-07-02 20:20:54 -07004587 LPWSTR remove = NULL;
4588 LPWSTR *features = NULL;
4589 BOOL full_uninstall = TRUE;
4590 MSIFEATURE *feature;
4591
James Hawkinscdb33f82008-06-23 23:02:54 -05004592 static const WCHAR szUpgradeCode[] =
4593 {'U','p','g','r','a','d','e','C','o','d','e',0};
James Hawkins624bbbe2007-07-02 20:20:54 -07004594
4595 remove = msi_dup_property(package, szRemove);
4596 if (!remove)
4597 return ERROR_SUCCESS;
4598
4599 features = msi_split_string(remove, ',');
4600 if (!features)
4601 {
4602 msi_free(remove);
4603 ERR("REMOVE feature list is empty!\n");
4604 return ERROR_FUNCTION_FAILED;
4605 }
4606
4607 if (!lstrcmpW(features[0], szAll))
4608 full_uninstall = TRUE;
4609 else
4610 {
4611 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4612 {
4613 if (feature->Action != INSTALLSTATE_ABSENT)
4614 full_uninstall = FALSE;
4615 }
4616 }
4617
4618 if (!full_uninstall)
4619 goto done;
4620
4621 MSIREG_DeleteProductKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004622 MSIREG_DeleteUserDataProductKey(package->ProductCode);
James Hawkinsf6b27672007-11-13 00:47:21 -06004623 MSIREG_DeleteUninstallKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004624
James Hawkins38106ac2008-07-28 18:46:32 -05004625 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4626 {
4627 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4628 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4629 }
4630 else
4631 {
4632 MSIREG_DeleteUserProductKey(package->ProductCode);
4633 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4634 }
4635
James Hawkinscdb33f82008-06-23 23:02:54 -05004636 upgrade = msi_dup_property(package, szUpgradeCode);
4637 if (upgrade)
4638 {
4639 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4640 msi_free(upgrade);
4641 }
4642
James Hawkins624bbbe2007-07-02 20:20:54 -07004643done:
4644 msi_free(remove);
4645 msi_free(features);
4646 return ERROR_SUCCESS;
4647}
4648
Aric Stewart2cae30b2005-01-19 19:07:40 +00004649static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4650{
Aric Stewart9cd707d2005-05-27 19:24:22 +00004651 UINT rc;
4652
James Hawkins624bbbe2007-07-02 20:20:54 -07004653 rc = msi_unpublish_product(package);
4654 if (rc != ERROR_SUCCESS)
4655 return rc;
4656
Francois Gouget1ccf9442006-11-12 19:51:37 +01004657 /* turn off scheduling */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004658 package->script->CurrentlyScripting= FALSE;
4659
Aric Stewart54c67dd2005-01-25 20:17:09 +00004660 /* first do the same as an InstallExecute */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004661 rc = ACTION_InstallExecute(package);
4662 if (rc != ERROR_SUCCESS)
4663 return rc;
Aric Stewart54c67dd2005-01-25 20:17:09 +00004664
4665 /* then handle Commit Actions */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004666 rc = execute_script(package,COMMIT_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004667
Aric Stewart9cd707d2005-05-27 19:24:22 +00004668 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004669}
4670
James Hawkinsc2e91582007-05-29 12:03:05 -07004671UINT ACTION_ForceReboot(MSIPACKAGE *package)
Aric Stewart2cae30b2005-01-19 19:07:40 +00004672{
4673 static const WCHAR RunOnce[] = {
4674 'S','o','f','t','w','a','r','e','\\',
4675 'M','i','c','r','o','s','o','f','t','\\',
4676 'W','i','n','d','o','w','s','\\',
4677 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004678 'R','u','n','O','n','c','e',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004679 static const WCHAR InstallRunOnce[] = {
4680 'S','o','f','t','w','a','r','e','\\',
4681 'M','i','c','r','o','s','o','f','t','\\',
4682 'W','i','n','d','o','w','s','\\',
4683 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4684 'I','n','s','t','a','l','l','e','r','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004685 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004686
4687 static const WCHAR msiexec_fmt[] = {
Juan Lang014ad3b2005-03-01 10:41:52 +00004688 '%','s',
Aric Stewart2cae30b2005-01-19 19:07:40 +00004689 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4690 '\"','%','s','\"',0};
4691 static const WCHAR install_fmt[] = {
4692 '/','I',' ','\"','%','s','\"',' ',
4693 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4694 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
Juan Lang014ad3b2005-03-01 10:41:52 +00004695 WCHAR buffer[256], sysdir[MAX_PATH];
Aric Stewartadaef112005-07-07 20:27:06 +00004696 HKEY hkey;
Mike McCormack4db02cd2005-09-15 14:58:38 +00004697 WCHAR squished_pc[100];
Aric Stewart2cae30b2005-01-19 19:07:40 +00004698
Aric Stewartadaef112005-07-07 20:27:06 +00004699 squash_guid(package->ProductCode,squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004700
Juan Lang014ad3b2005-03-01 10:41:52 +00004701 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
Aric Stewart2cae30b2005-01-19 19:07:40 +00004702 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
Juan Lang014ad3b2005-03-01 10:41:52 +00004703 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4704 squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004705
Mike McCormack4db02cd2005-09-15 14:58:38 +00004706 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004707 RegCloseKey(hkey);
4708
4709 TRACE("Reboot command %s\n",debugstr_w(buffer));
4710
4711 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
Aric Stewartadaef112005-07-07 20:27:06 +00004712 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004713
Mike McCormack4db02cd2005-09-15 14:58:38 +00004714 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004715 RegCloseKey(hkey);
4716
Aric Stewart68b07492005-01-25 11:05:37 +00004717 return ERROR_INSTALL_SUSPEND;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004718}
4719
James Hawkins563a50a2006-10-09 00:05:04 -07004720static UINT ACTION_ResolveSource(MSIPACKAGE* package)
Aric Stewart90c57392005-01-31 16:23:12 +00004721{
Mike McCormackb9211182006-11-20 16:27:36 +09004722 DWORD attrib;
Aric Stewart94d68182005-08-15 20:50:06 +00004723 UINT rc;
Mike McCormackfc564232006-11-20 16:17:03 +09004724
Aric Stewart90c57392005-01-31 16:23:12 +00004725 /*
Mike McCormackfc564232006-11-20 16:17:03 +09004726 * We are currently doing what should be done here in the top level Install
4727 * however for Administrative and uninstalls this step will be needed
Aric Stewart90c57392005-01-31 16:23:12 +00004728 */
Aric Stewart94d68182005-08-15 20:50:06 +00004729 if (!package->PackagePath)
4730 return ERROR_SUCCESS;
4731
James Hawkinsc777d302008-01-05 13:45:13 -07004732 msi_set_sourcedir_props(package, TRUE);
James Hawkinsc5075432006-10-10 13:39:50 -07004733
James Hawkinse28cedf2008-01-05 13:48:32 -07004734 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004735 if (attrib == INVALID_FILE_ATTRIBUTES)
4736 {
4737 LPWSTR prompt;
4738 LPWSTR msg;
4739 DWORD size = 0;
4740
4741 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004742 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004743 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4744 if (rc == ERROR_MORE_DATA)
4745 {
Mike McCormackee034ba2005-09-20 11:59:14 +00004746 prompt = msi_alloc(size * sizeof(WCHAR));
Aric Stewart94d68182005-08-15 20:50:06 +00004747 MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004748 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004749 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4750 }
4751 else
James Hawkinse28cedf2008-01-05 13:48:32 -07004752 prompt = strdupW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004753
4754 msg = generate_error_string(package,1302,1,prompt);
4755 while(attrib == INVALID_FILE_ATTRIBUTES)
4756 {
4757 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4758 if (rc == IDCANCEL)
4759 {
4760 rc = ERROR_INSTALL_USEREXIT;
4761 break;
4762 }
James Hawkinse28cedf2008-01-05 13:48:32 -07004763 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004764 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004765 msi_free(prompt);
Aric Stewart94d68182005-08-15 20:50:06 +00004766 rc = ERROR_SUCCESS;
4767 }
4768 else
4769 return ERROR_SUCCESS;
4770
4771 return rc;
Aric Stewart90c57392005-01-31 16:23:12 +00004772}
4773
Aric Stewartc7e88e02005-02-10 17:09:44 +00004774static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4775{
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004776 HKEY hkey = 0;
4777 LPWSTR buffer, productid = NULL;
4778 UINT i, rc = ERROR_SUCCESS;
4779 MSIRECORD *uirow;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004780
4781 static const WCHAR szPropKeys[][80] =
4782 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004783 {'P','r','o','d','u','c','t','I','D',0},
4784 {'U','S','E','R','N','A','M','E',0},
4785 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4786 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004787 };
4788
4789 static const WCHAR szRegKeys[][80] =
4790 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004791 {'P','r','o','d','u','c','t','I','D',0},
4792 {'R','e','g','O','w','n','e','r',0},
4793 {'R','e','g','C','o','m','p','a','n','y',0},
4794 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004795 };
4796
James Hawkinsd52f48f2008-03-06 16:12:40 -06004797 if (msi_check_unpublish(package))
4798 {
4799 MSIREG_DeleteUserDataProductKey(package->ProductCode);
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004800 goto end;
James Hawkinsd52f48f2008-03-06 16:12:40 -06004801 }
4802
Mike McCormack062ad502005-09-15 15:04:08 +00004803 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004804 if (!productid)
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004805 goto end;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004806
James Hawkinsb5e3e192008-12-14 21:07:14 -06004807 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4808 NULL, &hkey, TRUE);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004809 if (rc != ERROR_SUCCESS)
4810 goto end;
4811
Mike McCormack67189f92005-09-16 18:45:19 +00004812 for( i = 0; szPropKeys[i][0]; i++ )
Aric Stewartc7e88e02005-02-10 17:09:44 +00004813 {
Mike McCormack062ad502005-09-15 15:04:08 +00004814 buffer = msi_dup_property( package, szPropKeys[i] );
Mike McCormack4db02cd2005-09-15 14:58:38 +00004815 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00004816 msi_free( buffer );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004817 }
4818
4819end:
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004820 uirow = MSI_CreateRecord( 1 );
4821 MSI_RecordSetStringW( uirow, 1, productid );
4822 ui_actiondata( package, szRegisterUser, uirow );
4823 msiobj_release( &uirow->hdr );
4824
Mike McCormackee034ba2005-09-20 11:59:14 +00004825 msi_free(productid);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004826 RegCloseKey(hkey);
James Hawkinsd52f48f2008-03-06 16:12:40 -06004827 return rc;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004828}
4829
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004830
4831static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4832{
4833 UINT rc;
Aric Stewart25f1e752005-06-24 12:14:52 +00004834
Aric Stewartc9802932005-06-30 20:45:43 +00004835 package->script->InWhatSequence |= SEQUENCE_EXEC;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004836 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004837 return rc;
4838}
4839
Aric Stewart0af24872005-02-25 14:00:09 +00004840
Aric Stewart072c5e52005-04-20 12:50:05 +00004841static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4842{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01004843 MSIPACKAGE *package = param;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004844 LPCWSTR compgroupid, component, feature, qualifier, text;
4845 LPWSTR advertise = NULL, output = NULL;
Hans Leidekker353035f2010-03-04 09:17:50 +01004846 HKEY hkey = NULL;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004847 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00004848 MSICOMPONENT *comp;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004849 MSIFEATURE *feat;
4850 DWORD sz;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004851 MSIRECORD *uirow;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004852
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004853 feature = MSI_RecordGetString(rec, 5);
4854 feat = get_loaded_feature(package, feature);
4855 if (!feat)
Hans Leidekker598c5422010-02-16 11:44:47 +01004856 return ERROR_SUCCESS;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004857
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004858 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4859 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4860 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004861 {
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004862 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4863 feat->Action = feat->Installed;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004864 return ERROR_SUCCESS;
4865 }
Aric Stewart072c5e52005-04-20 12:50:05 +00004866
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004867 component = MSI_RecordGetString(rec, 3);
4868 comp = get_loaded_component(package, component);
4869 if (!comp)
4870 return ERROR_SUCCESS;
4871
Aric Stewart09b0aba2005-06-09 20:30:59 +00004872 compgroupid = MSI_RecordGetString(rec,1);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004873 qualifier = MSI_RecordGetString(rec,2);
Aric Stewart072c5e52005-04-20 12:50:05 +00004874
4875 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4876 if (rc != ERROR_SUCCESS)
4877 goto end;
4878
Aric Stewart09b0aba2005-06-09 20:30:59 +00004879 text = MSI_RecordGetString(rec,4);
Mike McCormack38d67a42005-08-22 09:15:23 +00004880 advertise = create_component_advertise_string(package, comp, feature);
Aric Stewart072c5e52005-04-20 12:50:05 +00004881
Aric Stewart6f43c182005-05-26 12:24:28 +00004882 sz = strlenW(advertise);
4883
Aric Stewart072c5e52005-04-20 12:50:05 +00004884 if (text)
4885 sz += lstrlenW(text);
Aric Stewart072c5e52005-04-20 12:50:05 +00004886
4887 sz+=3;
4888 sz *= sizeof(WCHAR);
4889
Mike McCormack3a940112006-04-19 02:29:03 +09004890 output = msi_alloc_zero(sz);
Aric Stewart6f43c182005-05-26 12:24:28 +00004891 strcpyW(output,advertise);
Mike McCormack470f23d2005-09-22 10:56:26 +00004892 msi_free(advertise);
Aric Stewart072c5e52005-04-20 12:50:05 +00004893
4894 if (text)
4895 strcatW(output,text);
4896
Mike McCormack4db02cd2005-09-15 14:58:38 +00004897 msi_reg_set_val_multi_str( hkey, qualifier, output );
Aric Stewart072c5e52005-04-20 12:50:05 +00004898
4899end:
4900 RegCloseKey(hkey);
Mike McCormackee034ba2005-09-20 11:59:14 +00004901 msi_free(output);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004902
4903 /* the UI chunk */
4904 uirow = MSI_CreateRecord( 2 );
4905 MSI_RecordSetStringW( uirow, 1, compgroupid );
4906 MSI_RecordSetStringW( uirow, 2, qualifier);
4907 ui_actiondata( package, szPublishComponents, uirow);
4908 msiobj_release( &uirow->hdr );
4909 /* FIXME: call ui_progress? */
4910
Aric Stewart072c5e52005-04-20 12:50:05 +00004911 return rc;
4912}
4913
4914/*
4915 * At present I am ignorning the advertised components part of this and only
4916 * focusing on the qualified component sets
4917 */
4918static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4919{
4920 UINT rc;
4921 MSIQUERY * view;
4922 static const WCHAR ExecSeqQuery[] =
4923 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00004924 '`','P','u','b','l','i','s','h',
4925 'C','o','m','p','o','n','e','n','t','`',0};
Aric Stewart072c5e52005-04-20 12:50:05 +00004926
4927 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4928 if (rc != ERROR_SUCCESS)
4929 return ERROR_SUCCESS;
4930
4931 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4932 msiobj_release(&view->hdr);
4933
4934 return rc;
4935}
Mike McCormack202166c2005-09-23 10:09:18 +00004936
Hans Leidekker0f0e81d2010-02-17 09:55:31 +01004937static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4938{
4939 static const WCHAR szInstallerComponents[] = {
4940 'S','o','f','t','w','a','r','e','\\',
4941 'M','i','c','r','o','s','o','f','t','\\',
4942 'I','n','s','t','a','l','l','e','r','\\',
4943 'C','o','m','p','o','n','e','n','t','s','\\',0};
4944
4945 MSIPACKAGE *package = param;
4946 LPCWSTR compgroupid, component, feature, qualifier;
4947 MSICOMPONENT *comp;
4948 MSIFEATURE *feat;
4949 MSIRECORD *uirow;
4950 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4951 LONG res;
4952
4953 feature = MSI_RecordGetString( rec, 5 );
4954 feat = get_loaded_feature( package, feature );
4955 if (!feat)
4956 return ERROR_SUCCESS;
4957
4958 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4959 {
4960 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4961 feat->Action = feat->Installed;
4962 return ERROR_SUCCESS;
4963 }
4964
4965 component = MSI_RecordGetString( rec, 3 );
4966 comp = get_loaded_component( package, component );
4967 if (!comp)
4968 return ERROR_SUCCESS;
4969
4970 compgroupid = MSI_RecordGetString( rec, 1 );
4971 qualifier = MSI_RecordGetString( rec, 2 );
4972
4973 squash_guid( compgroupid, squashed );
4974 strcpyW( keypath, szInstallerComponents );
4975 strcatW( keypath, squashed );
4976
4977 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4978 if (res != ERROR_SUCCESS)
4979 {
4980 WARN("Unable to delete component key %d\n", res);
4981 }
4982
4983 uirow = MSI_CreateRecord( 2 );
4984 MSI_RecordSetStringW( uirow, 1, compgroupid );
4985 MSI_RecordSetStringW( uirow, 2, qualifier );
4986 ui_actiondata( package, szUnpublishComponents, uirow );
4987 msiobj_release( &uirow->hdr );
4988
4989 return ERROR_SUCCESS;
4990}
4991
4992static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4993{
4994 UINT rc;
4995 MSIQUERY *view;
4996 static const WCHAR query[] =
4997 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4998 '`','P','u','b','l','i','s','h',
4999 'C','o','m','p','o','n','e','n','t','`',0};
5000
5001 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5002 if (rc != ERROR_SUCCESS)
5003 return ERROR_SUCCESS;
5004
5005 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5006 msiobj_release( &view->hdr );
5007
5008 return rc;
5009}
5010
James Hawkins9bc12ad2006-10-19 15:49:54 -07005011static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5012{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005013 MSIPACKAGE *package = param;
James Hawkins9bc12ad2006-10-19 15:49:54 -07005014 MSIRECORD *row;
5015 MSIFILE *file;
5016 SC_HANDLE hscm, service = NULL;
James Hawkinsde4cab22008-03-11 18:08:57 -05005017 LPCWSTR comp, depends, pass;
Marcus Meissnerdb71fb12008-03-13 21:54:48 +01005018 LPWSTR name = NULL, disp = NULL;
James Hawkins9bc12ad2006-10-19 15:49:54 -07005019 LPCWSTR load_order, serv_name, key;
5020 DWORD serv_type, start_type;
5021 DWORD err_control;
5022
5023 static const WCHAR query[] =
5024 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5025 '`','C','o','m','p','o','n','e','n','t','`',' ',
5026 'W','H','E','R','E',' ',
5027 '`','C','o','m','p','o','n','e','n','t','`',' ',
5028 '=','\'','%','s','\'',0};
5029
5030 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5031 if (!hscm)
5032 {
5033 ERR("Failed to open the SC Manager!\n");
5034 goto done;
5035 }
5036
5037 start_type = MSI_RecordGetInteger(rec, 5);
5038 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5039 goto done;
5040
5041 depends = MSI_RecordGetString(rec, 8);
5042 if (depends && *depends)
5043 FIXME("Dependency list unhandled!\n");
5044
James Hawkinsde4cab22008-03-11 18:08:57 -05005045 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5046 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005047 serv_type = MSI_RecordGetInteger(rec, 4);
5048 err_control = MSI_RecordGetInteger(rec, 6);
5049 load_order = MSI_RecordGetString(rec, 7);
5050 serv_name = MSI_RecordGetString(rec, 9);
5051 pass = MSI_RecordGetString(rec, 10);
5052 comp = MSI_RecordGetString(rec, 12);
5053
5054 /* fetch the service path */
5055 row = MSI_QueryGetRecord(package->db, query, comp);
5056 if (!row)
5057 {
5058 ERR("Control query failed!\n");
5059 goto done;
5060 }
5061
5062 key = MSI_RecordGetString(row, 6);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005063
5064 file = get_loaded_file(package, key);
James Hawkinsb6cfc402007-10-23 03:06:59 -05005065 msiobj_release(&row->hdr);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005066 if (!file)
5067 {
5068 ERR("Failed to load the service file\n");
5069 goto done;
5070 }
5071
5072 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5073 start_type, err_control, file->TargetPath,
5074 load_order, NULL, NULL, serv_name, pass);
5075 if (!service)
5076 {
5077 if (GetLastError() != ERROR_SERVICE_EXISTS)
5078 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5079 }
5080
5081done:
5082 CloseServiceHandle(service);
5083 CloseServiceHandle(hscm);
James Hawkinsde4cab22008-03-11 18:08:57 -05005084 msi_free(name);
5085 msi_free(disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005086
5087 return ERROR_SUCCESS;
5088}
5089
5090static UINT ACTION_InstallServices( MSIPACKAGE *package )
5091{
5092 UINT rc;
5093 MSIQUERY * view;
5094 static const WCHAR ExecSeqQuery[] =
5095 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5096 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5097
5098 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5099 if (rc != ERROR_SUCCESS)
5100 return ERROR_SUCCESS;
5101
5102 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5103 msiobj_release(&view->hdr);
5104
5105 return rc;
5106}
5107
James Hawkins58bb3572006-12-01 13:22:59 -08005108/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
James Hawkinscf8e9e32007-11-05 04:37:44 -05005109static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
James Hawkins58bb3572006-12-01 13:22:59 -08005110{
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005111 LPCWSTR *vector, *temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08005112 LPWSTR p, q;
5113 DWORD sep_len;
5114
5115 static const WCHAR separator[] = {'[','~',']',0};
5116
5117 *numargs = 0;
5118 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5119
5120 if (!args)
5121 return NULL;
5122
5123 vector = msi_alloc(sizeof(LPWSTR));
5124 if (!vector)
5125 return NULL;
5126
5127 p = args;
5128 do
5129 {
5130 (*numargs)++;
5131 vector[*numargs - 1] = p;
5132
5133 if ((q = strstrW(p, separator)))
5134 {
5135 *q = '\0';
5136
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005137 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5138 if (!temp_vector)
5139 {
5140 msi_free(vector);
James Hawkins58bb3572006-12-01 13:22:59 -08005141 return NULL;
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005142 }
5143 vector = temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08005144
5145 p = q + sep_len;
5146 }
5147 } while (q);
5148
5149 return vector;
5150}
5151
James Hawkins58bb3572006-12-01 13:22:59 -08005152static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5153{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005154 MSIPACKAGE *package = param;
James Hawkins58bb3572006-12-01 13:22:59 -08005155 MSICOMPONENT *comp;
Hans Leidekker129161f2010-03-26 12:11:21 +01005156 MSIRECORD *uirow;
Hans Leidekkerf7879b42010-02-12 10:33:23 +01005157 SC_HANDLE scm = NULL, service = NULL;
Hans Leidekker87448dc2010-03-02 14:56:01 +01005158 LPCWSTR component, *vector = NULL;
Hans Leidekker129161f2010-03-26 12:11:21 +01005159 LPWSTR name, args, display_name = NULL;
5160 DWORD event, numargs, len;
James Hawkins58bb3572006-12-01 13:22:59 -08005161 UINT r = ERROR_FUNCTION_FAILED;
5162
Hans Leidekker87448dc2010-03-02 14:56:01 +01005163 component = MSI_RecordGetString(rec, 6);
5164 comp = get_loaded_component(package, component);
5165 if (!comp)
James Hawkins58bb3572006-12-01 13:22:59 -08005166 return ERROR_SUCCESS;
5167
Hans Leidekker87448dc2010-03-02 14:56:01 +01005168 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5169 {
5170 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5171 comp->Action = comp->Installed;
5172 return ERROR_SUCCESS;
5173 }
5174 comp->Action = INSTALLSTATE_LOCAL;
5175
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005176 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5177 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
James Hawkins58bb3572006-12-01 13:22:59 -08005178 event = MSI_RecordGetInteger(rec, 3);
James Hawkins58bb3572006-12-01 13:22:59 -08005179
5180 if (!(event & msidbServiceControlEventStart))
Hans Leidekkerf7879b42010-02-12 10:33:23 +01005181 {
5182 r = ERROR_SUCCESS;
5183 goto done;
5184 }
James Hawkins58bb3572006-12-01 13:22:59 -08005185
5186 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5187 if (!scm)
5188 {
5189 ERR("Failed to open the service control manager\n");
5190 goto done;
5191 }
5192
Hans Leidekker129161f2010-03-26 12:11:21 +01005193 len = 0;
5194 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5195 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5196 {
5197 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5198 GetServiceDisplayNameW( scm, name, display_name, &len );
5199 }
5200
James Hawkins58bb3572006-12-01 13:22:59 -08005201 service = OpenServiceW(scm, name, SERVICE_START);
5202 if (!service)
5203 {
Hans Leidekkeraa196382010-01-28 11:06:05 +01005204 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
James Hawkins58bb3572006-12-01 13:22:59 -08005205 goto done;
5206 }
5207
James Hawkinscf8e9e32007-11-05 04:37:44 -05005208 vector = msi_service_args_to_vector(args, &numargs);
James Hawkins58bb3572006-12-01 13:22:59 -08005209
Hans Leidekker246f9302010-02-01 09:55:08 +01005210 if (!StartServiceW(service, numargs, vector) &&
5211 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
James Hawkins58bb3572006-12-01 13:22:59 -08005212 {
Hans Leidekkeraa196382010-01-28 11:06:05 +01005213 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
James Hawkins58bb3572006-12-01 13:22:59 -08005214 goto done;
5215 }
5216
5217 r = ERROR_SUCCESS;
5218
5219done:
Hans Leidekker129161f2010-03-26 12:11:21 +01005220 uirow = MSI_CreateRecord( 2 );
5221 MSI_RecordSetStringW( uirow, 1, display_name );
5222 MSI_RecordSetStringW( uirow, 2, name );
5223 ui_actiondata( package, szStartServices, uirow );
5224 msiobj_release( &uirow->hdr );
5225
James Hawkins58bb3572006-12-01 13:22:59 -08005226 CloseServiceHandle(service);
5227 CloseServiceHandle(scm);
5228
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005229 msi_free(name);
James Hawkins58bb3572006-12-01 13:22:59 -08005230 msi_free(args);
5231 msi_free(vector);
Hans Leidekker129161f2010-03-26 12:11:21 +01005232 msi_free(display_name);
James Hawkins58bb3572006-12-01 13:22:59 -08005233 return r;
5234}
5235
5236static UINT ACTION_StartServices( MSIPACKAGE *package )
5237{
5238 UINT rc;
5239 MSIQUERY *view;
5240
5241 static const WCHAR query[] = {
5242 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5243 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5244
5245 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5246 if (rc != ERROR_SUCCESS)
5247 return ERROR_SUCCESS;
5248
5249 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5250 msiobj_release(&view->hdr);
5251
5252 return rc;
5253}
5254
James Hawkinsfb508ff2008-03-24 01:31:07 -05005255static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5256{
5257 DWORD i, needed, count;
5258 ENUM_SERVICE_STATUSW *dependencies;
5259 SERVICE_STATUS ss;
5260 SC_HANDLE depserv;
5261
5262 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5263 0, &needed, &count))
5264 return TRUE;
5265
5266 if (GetLastError() != ERROR_MORE_DATA)
5267 return FALSE;
5268
5269 dependencies = msi_alloc(needed);
5270 if (!dependencies)
5271 return FALSE;
5272
5273 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5274 needed, &needed, &count))
5275 goto error;
5276
5277 for (i = 0; i < count; i++)
5278 {
5279 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5280 SERVICE_STOP | SERVICE_QUERY_STATUS);
5281 if (!depserv)
5282 goto error;
5283
5284 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5285 goto error;
5286 }
5287
5288 return TRUE;
5289
5290error:
5291 msi_free(dependencies);
5292 return FALSE;
5293}
5294
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005295static UINT stop_service( LPCWSTR name )
James Hawkinsfb508ff2008-03-24 01:31:07 -05005296{
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005297 SC_HANDLE scm = NULL, service = NULL;
James Hawkinsfb508ff2008-03-24 01:31:07 -05005298 SERVICE_STATUS status;
5299 SERVICE_STATUS_PROCESS ssp;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005300 DWORD needed;
James Hawkinsfb508ff2008-03-24 01:31:07 -05005301
5302 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5303 if (!scm)
5304 {
5305 WARN("Failed to open the SCM: %d\n", GetLastError());
5306 goto done;
5307 }
5308
5309 service = OpenServiceW(scm, name,
5310 SERVICE_STOP |
5311 SERVICE_QUERY_STATUS |
5312 SERVICE_ENUMERATE_DEPENDENTS);
5313 if (!service)
5314 {
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005315 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
James Hawkinsfb508ff2008-03-24 01:31:07 -05005316 goto done;
5317 }
5318
5319 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5320 sizeof(SERVICE_STATUS_PROCESS), &needed))
5321 {
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005322 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
James Hawkinsfb508ff2008-03-24 01:31:07 -05005323 goto done;
5324 }
5325
5326 if (ssp.dwCurrentState == SERVICE_STOPPED)
5327 goto done;
5328
5329 stop_service_dependents(scm, service);
5330
James Hawkinsddfefc02008-03-24 16:16:58 -05005331 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
James Hawkinsfb508ff2008-03-24 01:31:07 -05005332 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5333
5334done:
5335 CloseServiceHandle(service);
5336 CloseServiceHandle(scm);
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005337
5338 return ERROR_SUCCESS;
5339}
5340
5341static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5342{
5343 MSIPACKAGE *package = param;
5344 MSICOMPONENT *comp;
Hans Leidekker129161f2010-03-26 12:11:21 +01005345 MSIRECORD *uirow;
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005346 LPCWSTR component;
Hans Leidekker129161f2010-03-26 12:11:21 +01005347 LPWSTR name = NULL, display_name = NULL;
5348 DWORD event, len;
5349 SC_HANDLE scm;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005350
5351 event = MSI_RecordGetInteger( rec, 3 );
5352 if (!(event & msidbServiceControlEventStop))
5353 return ERROR_SUCCESS;
5354
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005355 component = MSI_RecordGetString( rec, 6 );
5356 comp = get_loaded_component( package, component );
5357 if (!comp)
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005358 return ERROR_SUCCESS;
5359
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005360 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5361 {
5362 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5363 comp->Action = comp->Installed;
5364 return ERROR_SUCCESS;
5365 }
5366 comp->Action = INSTALLSTATE_ABSENT;
5367
Hans Leidekker129161f2010-03-26 12:11:21 +01005368 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5369 if (!scm)
5370 {
5371 ERR("Failed to open the service control manager\n");
5372 goto done;
5373 }
5374
5375 len = 0;
5376 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5377 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5378 {
5379 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5380 GetServiceDisplayNameW( scm, name, display_name, &len );
5381 }
5382 CloseServiceHandle( scm );
5383
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005384 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5385 stop_service( name );
James Hawkinsfb508ff2008-03-24 01:31:07 -05005386
Hans Leidekker129161f2010-03-26 12:11:21 +01005387done:
5388 uirow = MSI_CreateRecord( 2 );
5389 MSI_RecordSetStringW( uirow, 1, display_name );
5390 MSI_RecordSetStringW( uirow, 2, name );
5391 ui_actiondata( package, szStopServices, uirow );
5392 msiobj_release( &uirow->hdr );
5393
5394 msi_free( name );
5395 msi_free( display_name );
James Hawkinsfb508ff2008-03-24 01:31:07 -05005396 return ERROR_SUCCESS;
5397}
5398
5399static UINT ACTION_StopServices( MSIPACKAGE *package )
5400{
5401 UINT rc;
5402 MSIQUERY *view;
5403
5404 static const WCHAR query[] = {
5405 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5406 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5407
5408 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5409 if (rc != ERROR_SUCCESS)
5410 return ERROR_SUCCESS;
5411
5412 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5413 msiobj_release(&view->hdr);
5414
5415 return rc;
5416}
5417
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005418static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5419{
5420 MSIPACKAGE *package = param;
5421 MSICOMPONENT *comp;
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005422 MSIRECORD *uirow;
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005423 LPCWSTR component;
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005424 LPWSTR name = NULL, display_name = NULL;
5425 DWORD event, len;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005426 SC_HANDLE scm = NULL, service = NULL;
5427
5428 event = MSI_RecordGetInteger( rec, 3 );
5429 if (!(event & msidbServiceControlEventDelete))
5430 return ERROR_SUCCESS;
5431
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005432 component = MSI_RecordGetString(rec, 6);
5433 comp = get_loaded_component(package, component);
5434 if (!comp)
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005435 return ERROR_SUCCESS;
5436
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005437 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5438 {
5439 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5440 comp->Action = comp->Installed;
5441 return ERROR_SUCCESS;
5442 }
5443 comp->Action = INSTALLSTATE_ABSENT;
5444
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005445 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5446 stop_service( name );
5447
5448 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5449 if (!scm)
5450 {
5451 WARN("Failed to open the SCM: %d\n", GetLastError());
5452 goto done;
5453 }
5454
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005455 len = 0;
5456 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5457 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5458 {
5459 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5460 GetServiceDisplayNameW( scm, name, display_name, &len );
5461 }
5462
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005463 service = OpenServiceW( scm, name, DELETE );
5464 if (!service)
5465 {
5466 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5467 goto done;
5468 }
5469
5470 if (!DeleteService( service ))
5471 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5472
5473done:
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005474 uirow = MSI_CreateRecord( 2 );
5475 MSI_RecordSetStringW( uirow, 1, display_name );
5476 MSI_RecordSetStringW( uirow, 2, name );
5477 ui_actiondata( package, szDeleteServices, uirow );
5478 msiobj_release( &uirow->hdr );
5479
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005480 CloseServiceHandle( service );
5481 CloseServiceHandle( scm );
5482 msi_free( name );
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005483 msi_free( display_name );
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005484
5485 return ERROR_SUCCESS;
5486}
5487
5488static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5489{
5490 UINT rc;
5491 MSIQUERY *view;
5492
5493 static const WCHAR query[] = {
5494 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5495 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5496
5497 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5498 if (rc != ERROR_SUCCESS)
5499 return ERROR_SUCCESS;
5500
5501 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5502 msiobj_release( &view->hdr );
5503
5504 return rc;
5505}
5506
James Hawkinsd3bec322006-11-27 18:20:33 -08005507static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5508{
5509 MSIFILE *file;
5510
5511 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5512 {
5513 if (!lstrcmpW(file->File, filename))
5514 return file;
5515 }
5516
5517 return NULL;
5518}
5519
5520static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5521{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005522 MSIPACKAGE *package = param;
James Hawkinsd3bec322006-11-27 18:20:33 -08005523 LPWSTR driver, driver_path, ptr;
5524 WCHAR outpath[MAX_PATH];
5525 MSIFILE *driver_file, *setup_file;
Hans Leidekkereff05032010-03-05 12:25:55 +01005526 MSIRECORD *uirow;
James Hawkinsd3bec322006-11-27 18:20:33 -08005527 LPCWSTR desc;
5528 DWORD len, usage;
5529 UINT r = ERROR_SUCCESS;
5530
5531 static const WCHAR driver_fmt[] = {
5532 'D','r','i','v','e','r','=','%','s',0};
5533 static const WCHAR setup_fmt[] = {
5534 'S','e','t','u','p','=','%','s',0};
5535 static const WCHAR usage_fmt[] = {
5536 'F','i','l','e','U','s','a','g','e','=','1',0};
5537
5538 desc = MSI_RecordGetString(rec, 3);
5539
5540 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5541 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5542
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005543 if (!driver_file)
James Hawkinsd3bec322006-11-27 18:20:33 -08005544 {
5545 ERR("ODBC Driver entry not found!\n");
5546 return ERROR_FUNCTION_FAILED;
5547 }
5548
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005549 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5550 if (setup_file)
5551 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
Hans Leidekker587e1072010-02-22 12:26:09 +01005552 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005553
James Hawkinsd3bec322006-11-27 18:20:33 -08005554 driver = msi_alloc(len * sizeof(WCHAR));
5555 if (!driver)
5556 return ERROR_OUTOFMEMORY;
5557
5558 ptr = driver;
5559 lstrcpyW(ptr, desc);
5560 ptr += lstrlenW(ptr) + 1;
5561
Hans Leidekker587e1072010-02-22 12:26:09 +01005562 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5563 ptr += len + 1;
James Hawkinsd3bec322006-11-27 18:20:33 -08005564
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005565 if (setup_file)
5566 {
Hans Leidekker587e1072010-02-22 12:26:09 +01005567 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5568 ptr += len + 1;
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005569 }
James Hawkinsd3bec322006-11-27 18:20:33 -08005570
5571 lstrcpyW(ptr, usage_fmt);
5572 ptr += lstrlenW(ptr) + 1;
5573 *ptr = '\0';
5574
5575 driver_path = strdupW(driver_file->TargetPath);
5576 ptr = strrchrW(driver_path, '\\');
5577 if (ptr) *ptr = '\0';
5578
5579 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5580 NULL, ODBC_INSTALL_COMPLETE, &usage))
5581 {
5582 ERR("Failed to install SQL driver!\n");
5583 r = ERROR_FUNCTION_FAILED;
5584 }
5585
Hans Leidekkereff05032010-03-05 12:25:55 +01005586 uirow = MSI_CreateRecord( 5 );
5587 MSI_RecordSetStringW( uirow, 1, desc );
5588 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5589 MSI_RecordSetStringW( uirow, 3, driver_path );
5590 ui_actiondata( package, szInstallODBC, uirow );
5591 msiobj_release( &uirow->hdr );
5592
James Hawkinsd3bec322006-11-27 18:20:33 -08005593 msi_free(driver);
5594 msi_free(driver_path);
5595
5596 return r;
5597}
5598
Hans Leidekker33c025b2007-04-22 11:37:51 +02005599static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5600{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005601 MSIPACKAGE *package = param;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005602 LPWSTR translator, translator_path, ptr;
5603 WCHAR outpath[MAX_PATH];
5604 MSIFILE *translator_file, *setup_file;
Hans Leidekkereff05032010-03-05 12:25:55 +01005605 MSIRECORD *uirow;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005606 LPCWSTR desc;
5607 DWORD len, usage;
5608 UINT r = ERROR_SUCCESS;
5609
5610 static const WCHAR translator_fmt[] = {
5611 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5612 static const WCHAR setup_fmt[] = {
5613 'S','e','t','u','p','=','%','s',0};
5614
5615 desc = MSI_RecordGetString(rec, 3);
5616
5617 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5618 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5619
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005620 if (!translator_file)
Hans Leidekker33c025b2007-04-22 11:37:51 +02005621 {
5622 ERR("ODBC Translator entry not found!\n");
5623 return ERROR_FUNCTION_FAILED;
5624 }
5625
Hans Leidekker587e1072010-02-22 12:26:09 +01005626 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005627 if (setup_file)
5628 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5629
Hans Leidekker33c025b2007-04-22 11:37:51 +02005630 translator = msi_alloc(len * sizeof(WCHAR));
5631 if (!translator)
5632 return ERROR_OUTOFMEMORY;
5633
5634 ptr = translator;
5635 lstrcpyW(ptr, desc);
5636 ptr += lstrlenW(ptr) + 1;
5637
Hans Leidekker587e1072010-02-22 12:26:09 +01005638 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5639 ptr += len + 1;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005640
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005641 if (setup_file)
5642 {
Hans Leidekker587e1072010-02-22 12:26:09 +01005643 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5644 ptr += len + 1;
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005645 }
Hans Leidekker33c025b2007-04-22 11:37:51 +02005646 *ptr = '\0';
5647
5648 translator_path = strdupW(translator_file->TargetPath);
5649 ptr = strrchrW(translator_path, '\\');
5650 if (ptr) *ptr = '\0';
5651
5652 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5653 NULL, ODBC_INSTALL_COMPLETE, &usage))
5654 {
5655 ERR("Failed to install SQL translator!\n");
5656 r = ERROR_FUNCTION_FAILED;
5657 }
5658
Hans Leidekkereff05032010-03-05 12:25:55 +01005659 uirow = MSI_CreateRecord( 5 );
5660 MSI_RecordSetStringW( uirow, 1, desc );
5661 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5662 MSI_RecordSetStringW( uirow, 3, translator_path );
5663 ui_actiondata( package, szInstallODBC, uirow );
5664 msiobj_release( &uirow->hdr );
5665
Hans Leidekker33c025b2007-04-22 11:37:51 +02005666 msi_free(translator);
5667 msi_free(translator_path);
5668
5669 return r;
5670}
5671
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005672static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5673{
Hans Leidekkereff05032010-03-05 12:25:55 +01005674 MSIPACKAGE *package = param;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005675 LPWSTR attrs;
5676 LPCWSTR desc, driver;
5677 WORD request = ODBC_ADD_SYS_DSN;
5678 INT registration;
5679 DWORD len;
5680 UINT r = ERROR_SUCCESS;
Hans Leidekkereff05032010-03-05 12:25:55 +01005681 MSIRECORD *uirow;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005682
5683 static const WCHAR attrs_fmt[] = {
5684 'D','S','N','=','%','s',0 };
5685
5686 desc = MSI_RecordGetString(rec, 3);
5687 driver = MSI_RecordGetString(rec, 4);
5688 registration = MSI_RecordGetInteger(rec, 5);
5689
5690 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5691 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5692
Hans Leidekker587e1072010-02-22 12:26:09 +01005693 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005694 attrs = msi_alloc(len * sizeof(WCHAR));
5695 if (!attrs)
5696 return ERROR_OUTOFMEMORY;
5697
Hans Leidekker2568e5e2010-02-11 13:13:19 +01005698 len = sprintfW(attrs, attrs_fmt, desc);
5699 attrs[len + 1] = 0;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005700
5701 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5702 {
5703 ERR("Failed to install SQL data source!\n");
5704 r = ERROR_FUNCTION_FAILED;
5705 }
5706
Hans Leidekkereff05032010-03-05 12:25:55 +01005707 uirow = MSI_CreateRecord( 5 );
5708 MSI_RecordSetStringW( uirow, 1, desc );
5709 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5710 MSI_RecordSetInteger( uirow, 3, request );
5711 ui_actiondata( package, szInstallODBC, uirow );
5712 msiobj_release( &uirow->hdr );
5713
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005714 msi_free(attrs);
5715
5716 return r;
5717}
5718
James Hawkinsd3bec322006-11-27 18:20:33 -08005719static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5720{
5721 UINT rc;
5722 MSIQUERY *view;
5723
Hans Leidekker33c025b2007-04-22 11:37:51 +02005724 static const WCHAR driver_query[] = {
James Hawkinsd3bec322006-11-27 18:20:33 -08005725 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5726 'O','D','B','C','D','r','i','v','e','r',0 };
5727
Hans Leidekker33c025b2007-04-22 11:37:51 +02005728 static const WCHAR translator_query[] = {
5729 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5730 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5731
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005732 static const WCHAR source_query[] = {
5733 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5734 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5735
Hans Leidekker33c025b2007-04-22 11:37:51 +02005736 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
James Hawkinsd3bec322006-11-27 18:20:33 -08005737 if (rc != ERROR_SUCCESS)
5738 return ERROR_SUCCESS;
5739
5740 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5741 msiobj_release(&view->hdr);
5742
Hans Leidekker33c025b2007-04-22 11:37:51 +02005743 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5744 if (rc != ERROR_SUCCESS)
5745 return ERROR_SUCCESS;
5746
5747 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5748 msiobj_release(&view->hdr);
5749
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005750 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5751 if (rc != ERROR_SUCCESS)
5752 return ERROR_SUCCESS;
5753
5754 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5755 msiobj_release(&view->hdr);
5756
James Hawkinsd3bec322006-11-27 18:20:33 -08005757 return rc;
5758}
5759
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005760static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5761{
Hans Leidekkera5549302010-03-05 12:26:21 +01005762 MSIPACKAGE *package = param;
5763 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005764 DWORD usage;
5765 LPCWSTR desc;
5766
5767 desc = MSI_RecordGetString( rec, 3 );
5768 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5769 {
5770 WARN("Failed to remove ODBC driver\n");
5771 }
5772 else if (!usage)
5773 {
5774 FIXME("Usage count reached 0\n");
5775 }
5776
Hans Leidekkera5549302010-03-05 12:26:21 +01005777 uirow = MSI_CreateRecord( 2 );
5778 MSI_RecordSetStringW( uirow, 1, desc );
5779 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5780 ui_actiondata( package, szRemoveODBC, uirow );
5781 msiobj_release( &uirow->hdr );
5782
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005783 return ERROR_SUCCESS;
5784}
5785
5786static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5787{
Hans Leidekkera5549302010-03-05 12:26:21 +01005788 MSIPACKAGE *package = param;
5789 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005790 DWORD usage;
5791 LPCWSTR desc;
5792
5793 desc = MSI_RecordGetString( rec, 3 );
5794 if (!SQLRemoveTranslatorW( desc, &usage ))
5795 {
5796 WARN("Failed to remove ODBC translator\n");
5797 }
5798 else if (!usage)
5799 {
5800 FIXME("Usage count reached 0\n");
5801 }
5802
Hans Leidekkera5549302010-03-05 12:26:21 +01005803 uirow = MSI_CreateRecord( 2 );
5804 MSI_RecordSetStringW( uirow, 1, desc );
5805 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5806 ui_actiondata( package, szRemoveODBC, uirow );
5807 msiobj_release( &uirow->hdr );
5808
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005809 return ERROR_SUCCESS;
5810}
5811
5812static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5813{
Hans Leidekkera5549302010-03-05 12:26:21 +01005814 MSIPACKAGE *package = param;
5815 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005816 LPWSTR attrs;
5817 LPCWSTR desc, driver;
5818 WORD request = ODBC_REMOVE_SYS_DSN;
5819 INT registration;
5820 DWORD len;
5821
5822 static const WCHAR attrs_fmt[] = {
5823 'D','S','N','=','%','s',0 };
5824
5825 desc = MSI_RecordGetString( rec, 3 );
5826 driver = MSI_RecordGetString( rec, 4 );
5827 registration = MSI_RecordGetInteger( rec, 5 );
5828
5829 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5830 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5831
Hans Leidekker587e1072010-02-22 12:26:09 +01005832 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005833 attrs = msi_alloc( len * sizeof(WCHAR) );
5834 if (!attrs)
5835 return ERROR_OUTOFMEMORY;
5836
5837 FIXME("Use ODBCSourceAttribute table\n");
5838
5839 len = sprintfW( attrs, attrs_fmt, desc );
5840 attrs[len + 1] = 0;
5841
5842 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5843 {
5844 WARN("Failed to remove ODBC data source\n");
5845 }
5846 msi_free( attrs );
5847
Hans Leidekkera5549302010-03-05 12:26:21 +01005848 uirow = MSI_CreateRecord( 3 );
5849 MSI_RecordSetStringW( uirow, 1, desc );
5850 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5851 MSI_RecordSetInteger( uirow, 3, request );
5852 ui_actiondata( package, szRemoveODBC, uirow );
5853 msiobj_release( &uirow->hdr );
5854
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005855 return ERROR_SUCCESS;
5856}
5857
5858static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5859{
5860 UINT rc;
5861 MSIQUERY *view;
5862
5863 static const WCHAR driver_query[] = {
5864 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5865 'O','D','B','C','D','r','i','v','e','r',0 };
5866
5867 static const WCHAR translator_query[] = {
5868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5869 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5870
5871 static const WCHAR source_query[] = {
5872 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5873 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5874
5875 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5876 if (rc != ERROR_SUCCESS)
5877 return ERROR_SUCCESS;
5878
5879 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5880 msiobj_release( &view->hdr );
5881
5882 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5883 if (rc != ERROR_SUCCESS)
5884 return ERROR_SUCCESS;
5885
5886 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5887 msiobj_release( &view->hdr );
5888
5889 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5890 if (rc != ERROR_SUCCESS)
5891 return ERROR_SUCCESS;
5892
5893 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5894 msiobj_release( &view->hdr );
5895
5896 return rc;
5897}
5898
James Hawkins5b8641a2007-05-30 10:57:31 -07005899#define ENV_ACT_SETALWAYS 0x1
5900#define ENV_ACT_SETABSENT 0x2
5901#define ENV_ACT_REMOVE 0x4
James Hawkins881f5922007-06-13 17:46:09 -07005902#define ENV_ACT_REMOVEMATCH 0x8
James Hawkins5b8641a2007-05-30 10:57:31 -07005903
5904#define ENV_MOD_MACHINE 0x20000000
5905#define ENV_MOD_APPEND 0x40000000
5906#define ENV_MOD_PREFIX 0x80000000
James Hawkins881f5922007-06-13 17:46:09 -07005907#define ENV_MOD_MASK 0xC0000000
5908
5909#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5910
Hans Leidekkerf6221112010-03-03 14:38:06 +01005911static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
James Hawkins881f5922007-06-13 17:46:09 -07005912{
5913 LPCWSTR cptr = *name;
James Hawkins881f5922007-06-13 17:46:09 -07005914
5915 static const WCHAR prefix[] = {'[','~',']',0};
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005916 static const int prefix_len = 3;
James Hawkins881f5922007-06-13 17:46:09 -07005917
5918 *flags = 0;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005919 while (*cptr)
James Hawkins881f5922007-06-13 17:46:09 -07005920 {
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005921 if (*cptr == '=')
James Hawkins881f5922007-06-13 17:46:09 -07005922 *flags |= ENV_ACT_SETALWAYS;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005923 else if (*cptr == '+')
James Hawkins881f5922007-06-13 17:46:09 -07005924 *flags |= ENV_ACT_SETABSENT;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005925 else if (*cptr == '-')
James Hawkins881f5922007-06-13 17:46:09 -07005926 *flags |= ENV_ACT_REMOVE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005927 else if (*cptr == '!')
James Hawkins881f5922007-06-13 17:46:09 -07005928 *flags |= ENV_ACT_REMOVEMATCH;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005929 else if (*cptr == '*')
James Hawkins881f5922007-06-13 17:46:09 -07005930 *flags |= ENV_MOD_MACHINE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005931 else
James Hawkins881f5922007-06-13 17:46:09 -07005932 break;
James Hawkins881f5922007-06-13 17:46:09 -07005933
5934 cptr++;
5935 (*name)++;
5936 }
5937
5938 if (!*cptr)
5939 {
5940 ERR("Missing environment variable\n");
5941 return ERROR_FUNCTION_FAILED;
5942 }
5943
Hans Leidekkere52531a2009-11-13 11:06:12 +01005944 if (*value)
James Hawkins881f5922007-06-13 17:46:09 -07005945 {
Hans Leidekkere52531a2009-11-13 11:06:12 +01005946 LPCWSTR ptr = *value;
5947 if (!strncmpW(ptr, prefix, prefix_len))
James Hawkins881f5922007-06-13 17:46:09 -07005948 {
Jason Edmeades06c45a82010-01-20 09:40:37 +00005949 if (ptr[prefix_len] == szSemiColon[0])
5950 {
5951 *flags |= ENV_MOD_APPEND;
5952 *value += lstrlenW(prefix);
5953 }
5954 else
5955 {
5956 *value = NULL;
5957 }
Hans Leidekkere52531a2009-11-13 11:06:12 +01005958 }
5959 else if (lstrlenW(*value) >= prefix_len)
5960 {
5961 ptr += lstrlenW(ptr) - prefix_len;
5962 if (!lstrcmpW(ptr, prefix))
5963 {
Jason Edmeades06c45a82010-01-20 09:40:37 +00005964 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5965 {
5966 *flags |= ENV_MOD_PREFIX;
5967 /* the "[~]" will be removed by deformat_string */;
5968 }
5969 else
5970 {
5971 *value = NULL;
5972 }
Hans Leidekkere52531a2009-11-13 11:06:12 +01005973 }
James Hawkins881f5922007-06-13 17:46:09 -07005974 }
5975 }
5976
Hans Leidekker659768e2009-09-15 20:52:39 +02005977 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
James Hawkins881f5922007-06-13 17:46:09 -07005978 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5979 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5980 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5981 {
5982 ERR("Invalid flags: %08x\n", *flags);
5983 return ERROR_FUNCTION_FAILED;
5984 }
5985
Hans Leidekker659768e2009-09-15 20:52:39 +02005986 if (!*flags)
5987 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5988
James Hawkins881f5922007-06-13 17:46:09 -07005989 return ERROR_SUCCESS;
5990}
James Hawkins5b8641a2007-05-30 10:57:31 -07005991
Hans Leidekkerf6221112010-03-03 14:38:06 +01005992static UINT open_env_key( DWORD flags, HKEY *key )
James Hawkins5b8641a2007-05-30 10:57:31 -07005993{
James Hawkins9d712382007-11-05 04:47:12 -05005994 static const WCHAR user_env[] =
5995 {'E','n','v','i','r','o','n','m','e','n','t',0};
5996 static const WCHAR machine_env[] =
James Hawkins5b8641a2007-05-30 10:57:31 -07005997 {'S','y','s','t','e','m','\\',
5998 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5999 'C','o','n','t','r','o','l','\\',
6000 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6001 'E','n','v','i','r','o','n','m','e','n','t',0};
Hans Leidekkerf6221112010-03-03 14:38:06 +01006002 const WCHAR *env;
6003 HKEY root;
6004 LONG res;
6005
6006 if (flags & ENV_MOD_MACHINE)
6007 {
6008 env = machine_env;
6009 root = HKEY_LOCAL_MACHINE;
6010 }
6011 else
6012 {
6013 env = user_env;
6014 root = HKEY_CURRENT_USER;
6015 }
6016
6017 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6018 if (res != ERROR_SUCCESS)
6019 {
6020 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6021 return ERROR_FUNCTION_FAILED;
6022 }
6023
6024 return ERROR_SUCCESS;
6025}
6026
6027static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6028{
6029 MSIPACKAGE *package = param;
6030 LPCWSTR name, value, component;
6031 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6032 DWORD flags, type, size;
6033 UINT res;
Hans Leidekker353035f2010-03-04 09:17:50 +01006034 HKEY env = NULL;
Hans Leidekkerf6221112010-03-03 14:38:06 +01006035 MSICOMPONENT *comp;
6036 MSIRECORD *uirow;
6037 int action = 0;
James Hawkins5b8641a2007-05-30 10:57:31 -07006038
Hans Leidekkerc8308ef2010-03-02 14:55:31 +01006039 component = MSI_RecordGetString(rec, 4);
6040 comp = get_loaded_component(package, component);
6041 if (!comp)
6042 return ERROR_SUCCESS;
6043
6044 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6045 {
6046 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6047 comp->Action = comp->Installed;
6048 return ERROR_SUCCESS;
6049 }
6050 comp->Action = INSTALLSTATE_LOCAL;
6051
James Hawkins881f5922007-06-13 17:46:09 -07006052 name = MSI_RecordGetString(rec, 2);
6053 value = MSI_RecordGetString(rec, 3);
James Hawkins5b8641a2007-05-30 10:57:31 -07006054
Hans Leidekker659768e2009-09-15 20:52:39 +02006055 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6056
Hans Leidekkerf6221112010-03-03 14:38:06 +01006057 res = env_parse_flags(&name, &value, &flags);
Jason Edmeades06c45a82010-01-20 09:40:37 +00006058 if (res != ERROR_SUCCESS || !value)
James Hawkins881f5922007-06-13 17:46:09 -07006059 goto done;
6060
Hans Leidekkere52531a2009-11-13 11:06:12 +01006061 if (value && !deformat_string(package, value, &deformatted))
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07006062 {
6063 res = ERROR_OUTOFMEMORY;
6064 goto done;
6065 }
6066
James Hawkins881f5922007-06-13 17:46:09 -07006067 value = deformatted;
James Hawkins5b8641a2007-05-30 10:57:31 -07006068
Hans Leidekkerf6221112010-03-03 14:38:06 +01006069 res = open_env_key( flags, &env );
James Hawkins5b8641a2007-05-30 10:57:31 -07006070 if (res != ERROR_SUCCESS)
James Hawkins881f5922007-06-13 17:46:09 -07006071 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07006072
Hans Leidekkerf6221112010-03-03 14:38:06 +01006073 if (flags & ENV_MOD_MACHINE)
6074 action |= 0x20000000;
James Hawkins5b8641a2007-05-30 10:57:31 -07006075
6076 size = 0;
James Hawkins26d541b2009-12-16 19:05:27 -08006077 type = REG_SZ;
James Hawkins881f5922007-06-13 17:46:09 -07006078 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6079 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
James Hawkins31c461e2008-01-05 11:46:09 -06006080 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
James Hawkins881f5922007-06-13 17:46:09 -07006081 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07006082
James Hawkins1b7238a2009-12-15 18:19:19 -08006083 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6084 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006085 action = 0x2;
6086
James Hawkins1b7238a2009-12-15 18:19:19 -08006087 /* Nothing to do. */
6088 if (!value)
6089 {
6090 res = ERROR_SUCCESS;
6091 goto done;
6092 }
6093
Jason Edmeades06c45a82010-01-20 09:40:37 +00006094 /* If we are appending but the string was empty, strip ; */
6095 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6096
James Hawkins1b7238a2009-12-15 18:19:19 -08006097 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6098 newval = strdupW(value);
6099 if (!newval)
6100 {
6101 res = ERROR_OUTOFMEMORY;
6102 goto done;
6103 }
6104 }
6105 else
James Hawkins5b8641a2007-05-30 10:57:31 -07006106 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006107 action = 0x1;
6108
Jason Edmeades06c45a82010-01-20 09:40:37 +00006109 /* Contrary to MSDN, +-variable to [~];path works */
6110 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
James Hawkins5b8641a2007-05-30 10:57:31 -07006111 {
6112 res = ERROR_SUCCESS;
6113 goto done;
6114 }
6115
James Hawkins881f5922007-06-13 17:46:09 -07006116 data = msi_alloc(size);
6117 if (!data)
6118 {
6119 RegCloseKey(env);
6120 return ERROR_OUTOFMEMORY;
6121 }
6122
6123 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6124 if (res != ERROR_SUCCESS)
6125 goto done;
6126
6127 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6128 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006129 action = 0x4;
6130 res = RegDeleteValueW(env, name);
6131 if (res != ERROR_SUCCESS)
6132 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
James Hawkins881f5922007-06-13 17:46:09 -07006133 goto done;
6134 }
6135
James Hawkins1b7238a2009-12-15 18:19:19 -08006136 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6137 if (flags & ENV_MOD_MASK)
6138 {
6139 DWORD mod_size;
6140 int multiplier = 0;
6141 if (flags & ENV_MOD_APPEND) multiplier++;
6142 if (flags & ENV_MOD_PREFIX) multiplier++;
Jason Edmeades06c45a82010-01-20 09:40:37 +00006143 mod_size = lstrlenW(value) * multiplier;
James Hawkins1b7238a2009-12-15 18:19:19 -08006144 size += mod_size * sizeof(WCHAR);
6145 }
6146
6147 newval = msi_alloc(size);
James Hawkins881f5922007-06-13 17:46:09 -07006148 ptr = newval;
6149 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07006150 {
6151 res = ERROR_OUTOFMEMORY;
6152 goto done;
6153 }
6154
James Hawkins1b7238a2009-12-15 18:19:19 -08006155 if (flags & ENV_MOD_PREFIX)
6156 {
James Hawkins881f5922007-06-13 17:46:09 -07006157 lstrcpyW(newval, value);
Jason Edmeades06c45a82010-01-20 09:40:37 +00006158 ptr = newval + lstrlenW(value);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006159 action |= 0x80000000;
James Hawkins5b8641a2007-05-30 10:57:31 -07006160 }
6161
James Hawkins1b7238a2009-12-15 18:19:19 -08006162 lstrcpyW(ptr, data);
6163
6164 if (flags & ENV_MOD_APPEND)
6165 {
James Hawkins1b7238a2009-12-15 18:19:19 -08006166 lstrcatW(newval, value);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006167 action |= 0x40000000;
James Hawkins1b7238a2009-12-15 18:19:19 -08006168 }
James Hawkins5b8641a2007-05-30 10:57:31 -07006169 }
Marcus Meissnere2f79462009-12-22 09:32:03 +01006170 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6171 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006172 if (res)
6173 {
6174 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6175 }
James Hawkins5b8641a2007-05-30 10:57:31 -07006176
6177done:
Hans Leidekkerf6221112010-03-03 14:38:06 +01006178 uirow = MSI_CreateRecord( 3 );
6179 MSI_RecordSetStringW( uirow, 1, name );
6180 MSI_RecordSetStringW( uirow, 2, newval );
6181 MSI_RecordSetInteger( uirow, 3, action );
6182 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6183 msiobj_release( &uirow->hdr );
6184
Andrew Talbot0e4ccb82007-06-23 17:28:50 +01006185 if (env) RegCloseKey(env);
James Hawkins881f5922007-06-13 17:46:09 -07006186 msi_free(deformatted);
6187 msi_free(data);
6188 msi_free(newval);
James Hawkins5b8641a2007-05-30 10:57:31 -07006189 return res;
6190}
6191
6192static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6193{
6194 UINT rc;
6195 MSIQUERY * view;
6196 static const WCHAR ExecSeqQuery[] =
6197 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6198 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6199 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6200 if (rc != ERROR_SUCCESS)
6201 return ERROR_SUCCESS;
6202
6203 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6204 msiobj_release(&view->hdr);
6205
6206 return rc;
6207}
6208
Hans Leidekkerf6221112010-03-03 14:38:06 +01006209static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6210{
6211 MSIPACKAGE *package = param;
6212 LPCWSTR name, value, component;
6213 LPWSTR deformatted = NULL;
6214 DWORD flags;
6215 HKEY env;
6216 MSICOMPONENT *comp;
6217 MSIRECORD *uirow;
6218 int action = 0;
6219 LONG res;
6220 UINT r;
6221
6222 component = MSI_RecordGetString( rec, 4 );
6223 comp = get_loaded_component( package, component );
6224 if (!comp)
6225 return ERROR_SUCCESS;
6226
6227 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6228 {
6229 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6230 comp->Action = comp->Installed;
6231 return ERROR_SUCCESS;
6232 }
6233 comp->Action = INSTALLSTATE_ABSENT;
6234
6235 name = MSI_RecordGetString( rec, 2 );
6236 value = MSI_RecordGetString( rec, 3 );
6237
6238 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6239
6240 r = env_parse_flags( &name, &value, &flags );
6241 if (r != ERROR_SUCCESS)
6242 return r;
6243
6244 if (!(flags & ENV_ACT_REMOVE))
6245 {
6246 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6247 return ERROR_SUCCESS;
6248 }
6249
6250 if (value && !deformat_string( package, value, &deformatted ))
6251 return ERROR_OUTOFMEMORY;
6252
6253 value = deformatted;
6254
6255 r = open_env_key( flags, &env );
6256 if (r != ERROR_SUCCESS)
6257 {
6258 r = ERROR_SUCCESS;
6259 goto done;
6260 }
6261
6262 if (flags & ENV_MOD_MACHINE)
6263 action |= 0x20000000;
6264
6265 TRACE("Removing %s\n", debugstr_w(name));
6266
6267 res = RegDeleteValueW( env, name );
6268 if (res != ERROR_SUCCESS)
6269 {
6270 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6271 r = ERROR_SUCCESS;
6272 }
6273
6274done:
6275 uirow = MSI_CreateRecord( 3 );
6276 MSI_RecordSetStringW( uirow, 1, name );
6277 MSI_RecordSetStringW( uirow, 2, value );
6278 MSI_RecordSetInteger( uirow, 3, action );
6279 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6280 msiobj_release( &uirow->hdr );
6281
6282 if (env) RegCloseKey( env );
6283 msi_free( deformatted );
6284 return r;
6285}
6286
6287static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6288{
6289 UINT rc;
6290 MSIQUERY *view;
6291 static const WCHAR query[] =
6292 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6293 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6294
6295 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6296 if (rc != ERROR_SUCCESS)
6297 return ERROR_SUCCESS;
6298
6299 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6300 msiobj_release( &view->hdr );
6301
6302 return rc;
6303}
6304
James Hawkins74239fc2008-08-18 22:59:44 -05006305typedef struct tagMSIASSEMBLY
6306{
6307 struct list entry;
6308 MSICOMPONENT *component;
6309 MSIFEATURE *feature;
6310 MSIFILE *file;
6311 LPWSTR manifest;
6312 LPWSTR application;
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006313 LPWSTR display_name;
James Hawkins74239fc2008-08-18 22:59:44 -05006314 DWORD attributes;
6315 BOOL installed;
6316} MSIASSEMBLY;
6317
James Hawkinsbfe07d12008-04-30 04:22:46 -05006318static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6319 DWORD dwReserved);
6320static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6321 LPVOID pvReserved, HMODULE *phModDll);
6322
6323static BOOL init_functionpointers(void)
6324{
6325 HRESULT hr;
6326 HMODULE hfusion;
6327 HMODULE hmscoree;
6328
6329 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6330
6331 hmscoree = LoadLibraryA("mscoree.dll");
6332 if (!hmscoree)
6333 {
6334 WARN("mscoree.dll not available\n");
6335 return FALSE;
6336 }
6337
6338 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6339 if (!pLoadLibraryShim)
6340 {
6341 WARN("LoadLibraryShim not available\n");
6342 FreeLibrary(hmscoree);
6343 return FALSE;
6344 }
6345
6346 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6347 if (FAILED(hr))
6348 {
6349 WARN("fusion.dll not available\n");
6350 FreeLibrary(hmscoree);
6351 return FALSE;
6352 }
6353
6354 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6355
6356 FreeLibrary(hmscoree);
6357 return TRUE;
6358}
6359
James Hawkinsd596ae22008-08-25 00:07:18 -05006360static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6361 LPWSTR path)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006362{
6363 IAssemblyCache *cache;
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006364 MSIRECORD *uirow;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006365 HRESULT hr;
6366 UINT r = ERROR_FUNCTION_FAILED;
6367
James Hawkins74239fc2008-08-18 22:59:44 -05006368 TRACE("installing assembly: %s\n", debugstr_w(path));
6369
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006370 uirow = MSI_CreateRecord( 2 );
6371 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6372 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6373 msiobj_release( &uirow->hdr );
6374
James Hawkins74239fc2008-08-18 22:59:44 -05006375 if (assembly->feature)
James Hawkinsd596ae22008-08-25 00:07:18 -05006376 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
James Hawkins74239fc2008-08-18 22:59:44 -05006377
6378 if (assembly->manifest)
6379 FIXME("Manifest unhandled\n");
6380
6381 if (assembly->application)
6382 {
6383 FIXME("Assembly should be privately installed\n");
6384 return ERROR_SUCCESS;
6385 }
6386
6387 if (assembly->attributes == msidbAssemblyAttributesWin32)
6388 {
6389 FIXME("Win32 assemblies not handled\n");
6390 return ERROR_SUCCESS;
6391 }
6392
James Hawkinsbfe07d12008-04-30 04:22:46 -05006393 hr = pCreateAssemblyCache(&cache, 0);
6394 if (FAILED(hr))
6395 goto done;
6396
6397 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6398 if (FAILED(hr))
6399 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6400
6401 r = ERROR_SUCCESS;
6402
6403done:
6404 IAssemblyCache_Release(cache);
6405 return r;
6406}
6407
James Hawkins74239fc2008-08-18 22:59:44 -05006408typedef struct tagASSEMBLY_LIST
James Hawkinsbfe07d12008-04-30 04:22:46 -05006409{
James Hawkins74239fc2008-08-18 22:59:44 -05006410 MSIPACKAGE *package;
James Hawkins019f4af2008-10-29 03:18:14 -05006411 IAssemblyCache *cache;
James Hawkins74239fc2008-08-18 22:59:44 -05006412 struct list *assemblies;
6413} ASSEMBLY_LIST;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006414
James Hawkins019f4af2008-10-29 03:18:14 -05006415typedef struct tagASSEMBLY_NAME
6416{
6417 LPWSTR name;
6418 LPWSTR version;
6419 LPWSTR culture;
6420 LPWSTR pubkeytoken;
6421} ASSEMBLY_NAME;
6422
6423static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6424{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006425 ASSEMBLY_NAME *asmname = param;
James Hawkins019f4af2008-10-29 03:18:14 -05006426 LPCWSTR name = MSI_RecordGetString(rec, 2);
6427 LPWSTR val = msi_dup_record_field(rec, 3);
6428
6429 static const WCHAR Name[] = {'N','a','m','e',0};
6430 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6431 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6432 static const WCHAR PublicKeyToken[] = {
6433 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6434
Hans Leidekker43094e42009-02-19 14:05:25 +01006435 if (!strcmpiW(name, Name))
James Hawkins019f4af2008-10-29 03:18:14 -05006436 asmname->name = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006437 else if (!strcmpiW(name, Version))
James Hawkins019f4af2008-10-29 03:18:14 -05006438 asmname->version = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006439 else if (!strcmpiW(name, Culture))
James Hawkins019f4af2008-10-29 03:18:14 -05006440 asmname->culture = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006441 else if (!strcmpiW(name, PublicKeyToken))
James Hawkins019f4af2008-10-29 03:18:14 -05006442 asmname->pubkeytoken = val;
6443 else
6444 msi_free(val);
6445
6446 return ERROR_SUCCESS;
6447}
6448
6449static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6450{
6451 if (!*str)
6452 {
6453 *size = lstrlenW(append) + 1;
6454 *str = msi_alloc((*size) * sizeof(WCHAR));
6455 lstrcpyW(*str, append);
6456 return;
6457 }
6458
6459 (*size) += lstrlenW(append);
6460 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6461 lstrcatW(*str, append);
6462}
6463
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006464static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
James Hawkins019f4af2008-10-29 03:18:14 -05006465{
James Hawkins019f4af2008-10-29 03:18:14 -05006466 static const WCHAR separator[] = {',',' ',0};
6467 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6468 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006469 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
James Hawkins019f4af2008-10-29 03:18:14 -05006470 static const WCHAR query[] = {
6471 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6472 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6473 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6474 '=','\'','%','s','\'',0};
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006475 ASSEMBLY_NAME name;
6476 MSIQUERY *view;
6477 LPWSTR display_name;
6478 DWORD size;
6479 UINT r;
James Hawkins019f4af2008-10-29 03:18:14 -05006480
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006481 display_name = NULL;
6482 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
James Hawkins019f4af2008-10-29 03:18:14 -05006483
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006484 r = MSI_OpenQuery( db, &view, query, comp->Component );
James Hawkins019f4af2008-10-29 03:18:14 -05006485 if (r != ERROR_SUCCESS)
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006486 return NULL;
James Hawkins019f4af2008-10-29 03:18:14 -05006487
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006488 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6489 msiobj_release( &view->hdr );
James Hawkins019f4af2008-10-29 03:18:14 -05006490
6491 if (!name.name)
6492 {
6493 ERR("No assembly name specified!\n");
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006494 return NULL;
James Hawkins019f4af2008-10-29 03:18:14 -05006495 }
6496
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006497 append_str( &display_name, &size, name.name );
James Hawkins019f4af2008-10-29 03:18:14 -05006498
6499 if (name.version)
6500 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006501 append_str( &display_name, &size, separator );
6502 append_str( &display_name, &size, Version );
6503 append_str( &display_name, &size, name.version );
James Hawkins019f4af2008-10-29 03:18:14 -05006504 }
James Hawkins019f4af2008-10-29 03:18:14 -05006505 if (name.culture)
6506 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006507 append_str( &display_name, &size, separator );
6508 append_str( &display_name, &size, Culture );
6509 append_str( &display_name, &size, name.culture );
James Hawkins019f4af2008-10-29 03:18:14 -05006510 }
James Hawkins019f4af2008-10-29 03:18:14 -05006511 if (name.pubkeytoken)
6512 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006513 append_str( &display_name, &size, separator );
6514 append_str( &display_name, &size, PublicKeyToken );
6515 append_str( &display_name, &size, name.pubkeytoken );
James Hawkins019f4af2008-10-29 03:18:14 -05006516 }
6517
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006518 msi_free( name.name );
6519 msi_free( name.version );
6520 msi_free( name.culture );
6521 msi_free( name.pubkeytoken );
6522
6523 return display_name;
6524}
6525
6526static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6527{
6528 ASSEMBLY_INFO asminfo;
6529 LPWSTR disp;
6530 BOOL found = FALSE;
6531 HRESULT hr;
6532
6533 disp = get_assembly_display_name( db, comp );
6534 if (!disp)
6535 return FALSE;
6536
6537 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
James Hawkins019f4af2008-10-29 03:18:14 -05006538 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
James Hawkins019f4af2008-10-29 03:18:14 -05006539
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006540 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6541 if (SUCCEEDED(hr))
6542 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
James Hawkins019f4af2008-10-29 03:18:14 -05006543
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006544 msi_free( disp );
James Hawkins019f4af2008-10-29 03:18:14 -05006545 return found;
6546}
6547
James Hawkins74239fc2008-08-18 22:59:44 -05006548static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6549{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006550 ASSEMBLY_LIST *list = param;
James Hawkins74239fc2008-08-18 22:59:44 -05006551 MSIASSEMBLY *assembly;
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006552 LPCWSTR component;
James Hawkins74239fc2008-08-18 22:59:44 -05006553
6554 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6555 if (!assembly)
6556 return ERROR_OUTOFMEMORY;
6557
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006558 component = MSI_RecordGetString(rec, 1);
6559 assembly->component = get_loaded_component(list->package, component);
6560 if (!assembly->component)
6561 return ERROR_SUCCESS;
James Hawkins74239fc2008-08-18 22:59:44 -05006562
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006563 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6564 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006565 {
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006566 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6567 assembly->component->Action = assembly->component->Installed;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006568 return ERROR_SUCCESS;
6569 }
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006570 assembly->component->Action = assembly->component->ActionRequest;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006571
James Hawkins74239fc2008-08-18 22:59:44 -05006572 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6573 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006574
James Hawkins74239fc2008-08-18 22:59:44 -05006575 if (!assembly->file)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006576 {
James Hawkins74239fc2008-08-18 22:59:44 -05006577 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
James Hawkins70cd6bf2008-05-20 00:35:42 -05006578 return ERROR_FUNCTION_FAILED;
6579 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05006580
James Hawkins74239fc2008-08-18 22:59:44 -05006581 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6582 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6583 assembly->attributes = MSI_RecordGetInteger(rec, 5);
Hans Leidekker9c6e6ef2009-03-25 13:52:56 +01006584
6585 if (assembly->application)
6586 {
6587 WCHAR version[24];
6588 DWORD size = sizeof(version)/sizeof(WCHAR);
6589
6590 /* FIXME: we should probably check the manifest file here */
6591
6592 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
Hans Leidekker7d837b92009-05-29 15:13:57 +02006593 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
Hans Leidekker9c6e6ef2009-03-25 13:52:56 +01006594 {
6595 assembly->installed = TRUE;
6596 }
6597 }
6598 else
6599 assembly->installed = check_assembly_installed(list->package->db,
6600 list->cache,
6601 assembly->component);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006602
James Hawkins74239fc2008-08-18 22:59:44 -05006603 list_add_head(list->assemblies, &assembly->entry);
James Hawkins74239fc2008-08-18 22:59:44 -05006604 return ERROR_SUCCESS;
6605}
James Hawkins9460ae32008-05-13 18:24:48 -05006606
James Hawkins74239fc2008-08-18 22:59:44 -05006607static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6608{
James Hawkins019f4af2008-10-29 03:18:14 -05006609 IAssemblyCache *cache = NULL;
James Hawkins74239fc2008-08-18 22:59:44 -05006610 ASSEMBLY_LIST list;
James Hawkins019f4af2008-10-29 03:18:14 -05006611 MSIQUERY *view;
6612 HRESULT hr;
James Hawkins74239fc2008-08-18 22:59:44 -05006613 UINT r;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006614
James Hawkins74239fc2008-08-18 22:59:44 -05006615 static const WCHAR query[] =
6616 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6617 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6618
6619 r = MSI_DatabaseOpenViewW(package->db, query, &view);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006620 if (r != ERROR_SUCCESS)
James Hawkins74239fc2008-08-18 22:59:44 -05006621 return ERROR_SUCCESS;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006622
James Hawkins019f4af2008-10-29 03:18:14 -05006623 hr = pCreateAssemblyCache(&cache, 0);
6624 if (FAILED(hr))
6625 return ERROR_FUNCTION_FAILED;
6626
James Hawkins74239fc2008-08-18 22:59:44 -05006627 list.package = package;
James Hawkins019f4af2008-10-29 03:18:14 -05006628 list.cache = cache;
James Hawkins74239fc2008-08-18 22:59:44 -05006629 list.assemblies = assemblies;
6630
6631 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6632 msiobj_release(&view->hdr);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006633
James Hawkins019f4af2008-10-29 03:18:14 -05006634 IAssemblyCache_Release(cache);
6635
James Hawkinsbfe07d12008-04-30 04:22:46 -05006636 return r;
6637}
6638
James Hawkins74239fc2008-08-18 22:59:44 -05006639static void free_assemblies(struct list *assemblies)
6640{
6641 struct list *item, *cursor;
6642
6643 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6644 {
6645 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6646
6647 list_remove(&assembly->entry);
6648 msi_free(assembly->application);
6649 msi_free(assembly->manifest);
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006650 msi_free(assembly->display_name);
James Hawkins74239fc2008-08-18 22:59:44 -05006651 msi_free(assembly);
6652 }
6653}
6654
6655static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6656{
6657 MSIASSEMBLY *assembly;
6658
6659 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6660 {
6661 if (!lstrcmpW(assembly->file->File, file))
6662 {
6663 *out = assembly;
6664 return TRUE;
6665 }
6666 }
6667
6668 return FALSE;
6669}
6670
6671static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6672 LPWSTR *path, DWORD *attrs, PVOID user)
6673{
6674 MSIASSEMBLY *assembly;
6675 WCHAR temppath[MAX_PATH];
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006676 struct list *assemblies = user;
James Hawkins74239fc2008-08-18 22:59:44 -05006677 UINT r;
6678
6679 if (!find_assembly(assemblies, file, &assembly))
6680 return FALSE;
6681
6682 GetTempPathW(MAX_PATH, temppath);
6683 PathAddBackslashW(temppath);
6684 lstrcatW(temppath, assembly->file->FileName);
6685
6686 if (action == MSICABEXTRACT_BEGINEXTRACT)
6687 {
6688 if (assembly->installed)
6689 return FALSE;
6690
6691 *path = strdupW(temppath);
6692 *attrs = assembly->file->Attributes;
6693 }
6694 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6695 {
6696 assembly->installed = TRUE;
6697
James Hawkinsd596ae22008-08-25 00:07:18 -05006698 r = install_assembly(package, assembly, temppath);
James Hawkins74239fc2008-08-18 22:59:44 -05006699 if (r != ERROR_SUCCESS)
6700 ERR("Failed to install assembly\n");
6701 }
6702
6703 return TRUE;
6704}
6705
James Hawkinsbfe07d12008-04-30 04:22:46 -05006706static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6707{
James Hawkins74239fc2008-08-18 22:59:44 -05006708 UINT r;
6709 struct list assemblies = LIST_INIT(assemblies);
6710 MSIASSEMBLY *assembly;
6711 MSIMEDIAINFO *mi;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006712
James Hawkins019f4af2008-10-29 03:18:14 -05006713 if (!init_functionpointers() || !pCreateAssemblyCache)
6714 return ERROR_FUNCTION_FAILED;
6715
James Hawkins74239fc2008-08-18 22:59:44 -05006716 r = load_assemblies(package, &assemblies);
6717 if (r != ERROR_SUCCESS)
6718 goto done;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006719
James Hawkins74239fc2008-08-18 22:59:44 -05006720 if (list_empty(&assemblies))
6721 goto done;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006722
James Hawkins74239fc2008-08-18 22:59:44 -05006723 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6724 if (!mi)
6725 {
6726 r = ERROR_OUTOFMEMORY;
6727 goto done;
6728 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05006729
James Hawkins74239fc2008-08-18 22:59:44 -05006730 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6731 {
6732 if (assembly->installed && !mi->is_continuous)
6733 continue;
6734
6735 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6736 (assembly->file->IsCompressed && !mi->is_extracted))
6737 {
6738 MSICABDATA data;
6739
6740 r = ready_media(package, assembly->file, mi);
6741 if (r != ERROR_SUCCESS)
6742 {
6743 ERR("Failed to ready media\n");
6744 break;
6745 }
6746
6747 data.mi = mi;
6748 data.package = package;
6749 data.cb = installassembly_cb;
6750 data.user = &assemblies;
6751
6752 if (assembly->file->IsCompressed &&
6753 !msi_cabextract(package, mi, &data))
6754 {
6755 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6756 r = ERROR_FUNCTION_FAILED;
6757 break;
6758 }
6759 }
6760
6761 if (!assembly->file->IsCompressed)
6762 {
James Hawkinsd15fddf2008-10-06 22:26:20 -05006763 LPWSTR source = resolve_file_source(package, assembly->file);
James Hawkins74239fc2008-08-18 22:59:44 -05006764
James Hawkinsd15fddf2008-10-06 22:26:20 -05006765 r = install_assembly(package, assembly, source);
James Hawkins74239fc2008-08-18 22:59:44 -05006766 if (r != ERROR_SUCCESS)
6767 ERR("Failed to install assembly\n");
James Hawkinsd15fddf2008-10-06 22:26:20 -05006768
6769 msi_free(source);
James Hawkins74239fc2008-08-18 22:59:44 -05006770 }
6771
6772 /* FIXME: write Installer assembly reg values */
6773 }
6774
6775done:
6776 free_assemblies(&assemblies);
6777 return r;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006778}
6779
Hans Leidekker068cb122010-02-10 11:55:59 +01006780static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6781{
6782 LPWSTR key, template, id;
6783 UINT r = ERROR_SUCCESS;
6784
6785 id = msi_dup_property( package, szProductID );
6786 if (id)
6787 {
6788 msi_free( id );
6789 return ERROR_SUCCESS;
6790 }
6791 template = msi_dup_property( package, szPIDTemplate );
6792 key = msi_dup_property( package, szPIDKEY );
6793
6794 if (key && template)
6795 {
6796 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6797 r = MSI_SetPropertyW( package, szProductID, key );
6798 }
6799 msi_free( template );
6800 msi_free( key );
6801 return r;
6802}
6803
Hans Leidekker29f47292010-02-03 09:20:22 +01006804static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6805{
6806 TRACE("\n");
6807 package->need_reboot = 1;
6808 return ERROR_SUCCESS;
6809}
6810
Hans Leidekker5df62d02010-02-10 11:54:57 +01006811static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6812{
Hans Leidekkera64372c2010-03-02 14:55:06 +01006813 static const WCHAR szAvailableFreeReg[] =
6814 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
Hans Leidekker31d06642010-03-05 12:23:22 +01006815 MSIRECORD *uirow;
6816 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
Hans Leidekkera64372c2010-03-02 14:55:06 +01006817
Hans Leidekker31d06642010-03-05 12:23:22 +01006818 TRACE("%p %d kilobytes\n", package, space);
6819
6820 uirow = MSI_CreateRecord( 1 );
6821 MSI_RecordSetInteger( uirow, 1, space );
6822 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6823 msiobj_release( &uirow->hdr );
6824
Hans Leidekker5df62d02010-02-10 11:54:57 +01006825 return ERROR_SUCCESS;
6826}
6827
6828static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6829{
6830 FIXME("%p\n", package);
6831 return ERROR_SUCCESS;
6832}
6833
6834static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6835{
6836 FIXME("%p\n", package);
6837 return ERROR_SUCCESS;
6838}
6839
Hans Leidekker5a08c9e2010-03-26 12:12:35 +01006840static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6841{
6842 UINT r, count;
6843 MSIQUERY *view;
6844
6845 static const WCHAR driver_query[] = {
6846 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6847 'O','D','B','C','D','r','i','v','e','r',0 };
6848
6849 static const WCHAR translator_query[] = {
6850 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6851 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6852
6853 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6854 if (r == ERROR_SUCCESS)
6855 {
6856 count = 0;
6857 r = MSI_IterateRecords( view, &count, NULL, package );
6858 msiobj_release( &view->hdr );
6859 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6860 }
6861
6862 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6863 if (r == ERROR_SUCCESS)
6864 {
6865 count = 0;
6866 r = MSI_IterateRecords( view, &count, NULL, package );
6867 msiobj_release( &view->hdr );
6868 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6869 }
6870
6871 return ERROR_SUCCESS;
6872}
6873
Mike McCormack2586a092005-09-26 09:56:18 +00006874static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6875 LPCSTR action, LPCWSTR table )
Mike McCormack567f0312005-09-23 11:06:57 +00006876{
6877 static const WCHAR query[] = {
Mike McCormack2586a092005-09-26 09:56:18 +00006878 'S','E','L','E','C','T',' ','*',' ',
6879 'F','R','O','M',' ','`','%','s','`',0 };
Mike McCormack567f0312005-09-23 11:06:57 +00006880 MSIQUERY *view = NULL;
6881 DWORD count = 0;
Mike McCormack2586a092005-09-26 09:56:18 +00006882 UINT r;
Mike McCormack567f0312005-09-23 11:06:57 +00006883
Mike McCormack2586a092005-09-26 09:56:18 +00006884 r = MSI_OpenQuery( package->db, &view, query, table );
6885 if (r == ERROR_SUCCESS)
Mike McCormack567f0312005-09-23 11:06:57 +00006886 {
Mike McCormack2586a092005-09-26 09:56:18 +00006887 r = MSI_IterateRecords(view, &count, NULL, package);
Mike McCormack567f0312005-09-23 11:06:57 +00006888 msiobj_release(&view->hdr);
6889 }
6890
Mike McCormack2586a092005-09-26 09:56:18 +00006891 if (count)
Mike McCormackf1d46462006-10-05 13:41:22 +09006892 FIXME("%s -> %u ignored %s table values\n",
Mike McCormack2586a092005-09-26 09:56:18 +00006893 action, count, debugstr_w(table));
6894
Mike McCormack567f0312005-09-23 11:06:57 +00006895 return ERROR_SUCCESS;
6896}
Mike McCormack94fbe092005-09-23 17:21:10 +00006897
Mike McCormack2586a092005-09-26 09:56:18 +00006898static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6899{
6900 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6901 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6902}
6903
6904static UINT ACTION_BindImage( MSIPACKAGE *package )
6905{
6906 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6907 return msi_unimplemented_action_stub( package, "BindImage", table );
6908}
6909
6910static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6911{
6912 static const WCHAR table[] = {
Hans Leidekker930b5e12010-02-26 14:09:29 +01006913 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
Mike McCormack2586a092005-09-26 09:56:18 +00006914 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6915}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00006916
Mike McCormack2586a092005-09-26 09:56:18 +00006917static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6918{
6919 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6920 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6921}
6922
Mike McCormack3b955152005-09-28 18:10:44 +00006923static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6924{
6925 static const WCHAR table[] = {
6926 'M','s','i','A','s','s','e','m','b','l','y',0 };
6927 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6928}
6929
Mike McCormackf24a9e22005-12-31 13:14:23 +01006930static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6931{
6932 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6933 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6934}
6935
Mike McCormack88603662006-03-22 23:01:56 +09006936static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6937{
6938 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6939 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6940}
6941
6942static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6943{
6944 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6945 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6946}
6947
James Hawkins987c2c82007-05-06 20:52:14 -05006948static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6949{
6950 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6951 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6952}
6953
James Hawkins987c2c82007-05-06 20:52:14 -05006954static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6955{
6956 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6957 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6958}
6959
James Hawkins987c2c82007-05-06 20:52:14 -05006960static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6961{
6962 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6963 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6964}
6965
6966static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6967{
6968 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6969 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6970}
6971
6972static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6973{
6974 static const WCHAR table[] = { 'M','I','M','E',0 };
6975 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6976}
6977
6978static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6979{
6980 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6981 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6982}
6983
Hans Leidekker796eed12009-10-15 12:47:48 +02006984typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6985
6986static const struct
6987{
6988 const WCHAR *action;
6989 UINT (*handler)(MSIPACKAGE *);
6990}
6991StandardActions[] =
6992{
Mike McCormack55942702005-10-30 19:23:28 +00006993 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
Mike McCormack3b955152005-09-28 18:10:44 +00006994 { szAppSearch, ACTION_AppSearch },
6995 { szBindImage, ACTION_BindImage },
James Hawkins987c2c82007-05-06 20:52:14 -05006996 { szCCPSearch, ACTION_CCPSearch },
Mike McCormack3b955152005-09-28 18:10:44 +00006997 { szCostFinalize, ACTION_CostFinalize },
6998 { szCostInitialize, ACTION_CostInitialize },
6999 { szCreateFolders, ACTION_CreateFolders },
7000 { szCreateShortcuts, ACTION_CreateShortcuts },
7001 { szDeleteServices, ACTION_DeleteServices },
Hans Leidekker5df62d02010-02-10 11:54:57 +01007002 { szDisableRollback, ACTION_DisableRollback },
Mike McCormack3b955152005-09-28 18:10:44 +00007003 { szDuplicateFiles, ACTION_DuplicateFiles },
7004 { szExecuteAction, ACTION_ExecuteAction },
7005 { szFileCost, ACTION_FileCost },
7006 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7007 { szForceReboot, ACTION_ForceReboot },
Hans Leidekker5df62d02010-02-10 11:54:57 +01007008 { szInstallAdminPackage, ACTION_InstallAdminPackage },
Mike McCormack3b955152005-09-28 18:10:44 +00007009 { szInstallExecute, ACTION_InstallExecute },
7010 { szInstallExecuteAgain, ACTION_InstallExecute },
7011 { szInstallFiles, ACTION_InstallFiles},
7012 { szInstallFinalize, ACTION_InstallFinalize },
7013 { szInstallInitialize, ACTION_InstallInitialize },
James Hawkins987c2c82007-05-06 20:52:14 -05007014 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
Mike McCormack3b955152005-09-28 18:10:44 +00007015 { szInstallValidate, ACTION_InstallValidate },
7016 { szIsolateComponents, ACTION_IsolateComponents },
7017 { szLaunchConditions, ACTION_LaunchConditions },
7018 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7019 { szMoveFiles, ACTION_MoveFiles },
7020 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7021 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
James Hawkinsd3bec322006-11-27 18:20:33 -08007022 { szInstallODBC, ACTION_InstallODBC },
Mike McCormack3b955152005-09-28 18:10:44 +00007023 { szInstallServices, ACTION_InstallServices },
7024 { szPatchFiles, ACTION_PatchFiles },
7025 { szProcessComponents, ACTION_ProcessComponents },
7026 { szPublishComponents, ACTION_PublishComponents },
7027 { szPublishFeatures, ACTION_PublishFeatures },
7028 { szPublishProduct, ACTION_PublishProduct },
7029 { szRegisterClassInfo, ACTION_RegisterClassInfo },
Mike McCormack88603662006-03-22 23:01:56 +09007030 { szRegisterComPlus, ACTION_RegisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00007031 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7032 { szRegisterFonts, ACTION_RegisterFonts },
7033 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7034 { szRegisterProduct, ACTION_RegisterProduct },
7035 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7036 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
James Hawkins987c2c82007-05-06 20:52:14 -05007037 { szRegisterUser, ACTION_RegisterUser },
7038 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
Mike McCormack3b955152005-09-28 18:10:44 +00007039 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
James Hawkins987c2c82007-05-06 20:52:14 -05007040 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7041 { szRemoveFiles, ACTION_RemoveFiles },
7042 { szRemoveFolders, ACTION_RemoveFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00007043 { szRemoveIniValues, ACTION_RemoveIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05007044 { szRemoveODBC, ACTION_RemoveODBC },
7045 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7046 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7047 { szResolveSource, ACTION_ResolveSource },
7048 { szRMCCPSearch, ACTION_RMCCPSearch },
Hans Leidekker29f47292010-02-03 09:20:22 +01007049 { szScheduleReboot, ACTION_ScheduleReboot },
Mike McCormack3b955152005-09-28 18:10:44 +00007050 { szSelfRegModules, ACTION_SelfRegModules },
7051 { szSelfUnregModules, ACTION_SelfUnregModules },
Hans Leidekker552a9c92010-02-03 09:19:56 +01007052 { szSetODBCFolders, ACTION_SetODBCFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00007053 { szStartServices, ACTION_StartServices },
7054 { szStopServices, ACTION_StopServices },
James Hawkins987c2c82007-05-06 20:52:14 -05007055 { szUnpublishComponents, ACTION_UnpublishComponents },
7056 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7057 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7058 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7059 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
Mike McCormack3b955152005-09-28 18:10:44 +00007060 { szUnregisterFonts, ACTION_UnregisterFonts },
James Hawkins987c2c82007-05-06 20:52:14 -05007061 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7062 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7063 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7064 { szValidateProductID, ACTION_ValidateProductID },
Mike McCormack3b955152005-09-28 18:10:44 +00007065 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7066 { szWriteIniValues, ACTION_WriteIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05007067 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7068 { NULL, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00007069};
Andrew Talbot9e85ec32008-04-03 14:50:28 +01007070
7071static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7072 UINT* rc, BOOL force )
7073{
7074 BOOL ret = FALSE;
7075 BOOL run = force;
7076 int i;
7077
7078 if (!run && !package->script->CurrentlyScripting)
7079 run = TRUE;
7080
7081 if (!run)
7082 {
7083 if (strcmpW(action,szInstallFinalize) == 0 ||
7084 strcmpW(action,szInstallExecute) == 0 ||
7085 strcmpW(action,szInstallExecuteAgain) == 0)
7086 run = TRUE;
7087 }
7088
7089 i = 0;
7090 while (StandardActions[i].action != NULL)
7091 {
7092 if (strcmpW(StandardActions[i].action, action)==0)
7093 {
7094 if (!run)
7095 {
7096 ui_actioninfo(package, action, TRUE, 0);
7097 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7098 ui_actioninfo(package, action, FALSE, *rc);
7099 }
7100 else
7101 {
7102 ui_actionstart(package, action);
7103 if (StandardActions[i].handler)
7104 {
7105 *rc = StandardActions[i].handler(package);
7106 }
7107 else
7108 {
7109 FIXME("unhandled standard action %s\n",debugstr_w(action));
7110 *rc = ERROR_SUCCESS;
7111 }
7112 }
7113 ret = TRUE;
7114 break;
7115 }
7116 i++;
7117 }
7118 return ret;
7119}
Hans Leidekker796eed12009-10-15 12:47:48 +02007120
7121UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7122{
7123 UINT rc = ERROR_SUCCESS;
7124 BOOL handled;
7125
7126 TRACE("Performing action (%s)\n", debugstr_w(action));
7127
7128 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7129
7130 if (!handled)
7131 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7132
7133 if (!handled)
7134 {
7135 WARN("unhandled msi action %s\n", debugstr_w(action));
7136 rc = ERROR_FUNCTION_NOT_CALLED;
7137 }
7138
7139 return rc;
7140}
7141
7142UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7143{
7144 UINT rc = ERROR_SUCCESS;
7145 BOOL handled = FALSE;
7146
7147 TRACE("Performing action (%s)\n", debugstr_w(action));
7148
7149 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7150
7151 if (!handled)
7152 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7153
7154 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7155 handled = TRUE;
7156
7157 if (!handled)
7158 {
7159 WARN("unhandled msi action %s\n", debugstr_w(action));
7160 rc = ERROR_FUNCTION_NOT_CALLED;
7161 }
7162
7163 return rc;
7164}
7165
Hans Leidekkera187b432009-10-15 12:49:10 +02007166static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
Hans Leidekker796eed12009-10-15 12:47:48 +02007167{
7168 UINT rc = ERROR_SUCCESS;
Hans Leidekkera187b432009-10-15 12:49:10 +02007169 MSIRECORD *row;
Hans Leidekker796eed12009-10-15 12:47:48 +02007170
7171 static const WCHAR ExecSeqQuery[] =
7172 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7173 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7174 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7175 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7176 static const WCHAR UISeqQuery[] =
7177 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7178 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7179 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7180 ' ', '=',' ','%','i',0};
7181
Hans Leidekkera187b432009-10-15 12:49:10 +02007182 if (needs_ui_sequence(package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007183 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7184 else
7185 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7186
7187 if (row)
7188 {
7189 LPCWSTR action, cond;
7190
7191 TRACE("Running the actions\n");
7192
7193 /* check conditions */
7194 cond = MSI_RecordGetString(row, 2);
7195
7196 /* this is a hack to skip errors in the condition code */
7197 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
Hans Leidekkera187b432009-10-15 12:49:10 +02007198 {
7199 msiobj_release(&row->hdr);
7200 return ERROR_SUCCESS;
7201 }
Hans Leidekker796eed12009-10-15 12:47:48 +02007202
7203 action = MSI_RecordGetString(row, 1);
7204 if (!action)
7205 {
7206 ERR("failed to fetch action\n");
Hans Leidekkera187b432009-10-15 12:49:10 +02007207 msiobj_release(&row->hdr);
7208 return ERROR_FUNCTION_FAILED;
Hans Leidekker796eed12009-10-15 12:47:48 +02007209 }
7210
Hans Leidekkera187b432009-10-15 12:49:10 +02007211 if (needs_ui_sequence(package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007212 rc = ACTION_PerformUIAction(package, action, -1);
7213 else
7214 rc = ACTION_PerformAction(package, action, -1, FALSE);
Hans Leidekkera187b432009-10-15 12:49:10 +02007215
Hans Leidekker796eed12009-10-15 12:47:48 +02007216 msiobj_release(&row->hdr);
7217 }
Hans Leidekker796eed12009-10-15 12:47:48 +02007218
7219 return rc;
7220}
7221
7222/****************************************************
7223 * TOP level entry points
7224 *****************************************************/
7225
7226UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7227 LPCWSTR szCommandLine )
7228{
7229 UINT rc;
Hans Leidekkera187b432009-10-15 12:49:10 +02007230 BOOL ui_exists;
Hans Leidekker796eed12009-10-15 12:47:48 +02007231
7232 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7233 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7234
7235 MSI_SetPropertyW(package, szAction, szInstall);
7236
Hans Leidekker796eed12009-10-15 12:47:48 +02007237 package->script->InWhatSequence = SEQUENCE_INSTALL;
7238
7239 if (szPackagePath)
7240 {
7241 LPWSTR p, dir;
7242 LPCWSTR file;
7243
7244 dir = strdupW(szPackagePath);
7245 p = strrchrW(dir, '\\');
7246 if (p)
7247 {
7248 *(++p) = 0;
7249 file = szPackagePath + (p - dir);
7250 }
7251 else
7252 {
7253 msi_free(dir);
7254 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7255 GetCurrentDirectoryW(MAX_PATH, dir);
7256 lstrcatW(dir, szBackSlash);
7257 file = szPackagePath;
7258 }
7259
7260 msi_free( package->PackagePath );
7261 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7262 if (!package->PackagePath)
7263 {
7264 msi_free(dir);
7265 return ERROR_OUTOFMEMORY;
7266 }
7267
7268 lstrcpyW(package->PackagePath, dir);
7269 lstrcatW(package->PackagePath, file);
7270 msi_free(dir);
7271
7272 msi_set_sourcedir_props(package, FALSE);
7273 }
7274
7275 msi_parse_command_line( package, szCommandLine, FALSE );
7276
7277 msi_apply_transforms( package );
7278 msi_apply_patches( package );
7279
7280 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7281 {
7282 TRACE("setting reinstall property\n");
7283 MSI_SetPropertyW( package, szReinstall, szAll );
7284 }
7285
7286 /* properties may have been added by a transform */
7287 msi_clone_properties( package );
7288 msi_set_context( package );
7289
Hans Leidekkere3aa2f32009-10-15 12:48:26 +02007290 if (needs_ui_sequence( package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007291 {
7292 package->script->InWhatSequence |= SEQUENCE_UI;
7293 rc = ACTION_ProcessUISequence(package);
Hans Leidekker796eed12009-10-15 12:47:48 +02007294 ui_exists = ui_sequence_exists(package);
7295 if (rc == ERROR_SUCCESS || !ui_exists)
7296 {
7297 package->script->InWhatSequence |= SEQUENCE_EXEC;
7298 rc = ACTION_ProcessExecSequence(package, ui_exists);
7299 }
7300 }
7301 else
7302 rc = ACTION_ProcessExecSequence(package, FALSE);
7303
7304 package->script->CurrentlyScripting = FALSE;
7305
7306 /* process the ending type action */
7307 if (rc == ERROR_SUCCESS)
Hans Leidekkera187b432009-10-15 12:49:10 +02007308 ACTION_PerformActionSequence(package, -1);
Hans Leidekker796eed12009-10-15 12:47:48 +02007309 else if (rc == ERROR_INSTALL_USEREXIT)
Hans Leidekkera187b432009-10-15 12:49:10 +02007310 ACTION_PerformActionSequence(package, -2);
Hans Leidekker796eed12009-10-15 12:47:48 +02007311 else if (rc == ERROR_INSTALL_SUSPEND)
Hans Leidekkera187b432009-10-15 12:49:10 +02007312 ACTION_PerformActionSequence(package, -4);
Hans Leidekker796eed12009-10-15 12:47:48 +02007313 else /* failed */
Hans Leidekkera187b432009-10-15 12:49:10 +02007314 ACTION_PerformActionSequence(package, -3);
Hans Leidekker796eed12009-10-15 12:47:48 +02007315
7316 /* finish up running custom actions */
7317 ACTION_FinishCustomActions(package);
7318
7319 if (rc == ERROR_SUCCESS && package->need_reboot)
7320 return ERROR_SUCCESS_REBOOT_REQUIRED;
7321
7322 return rc;
7323}