blob: a03b179e4ed41acc800cccf378366f53340a6ee8 [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);
2365
2366 if (type == REG_SZ)
2367 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2368 else
2369 MSI_RecordSetStringW(uirow,3,value);
2370
2371 ui_actiondata(package,szWriteRegistryValues,uirow);
2372 msiobj_release( &uirow->hdr );
2373
Mike McCormackee034ba2005-09-20 11:59:14 +00002374 msi_free(value_data);
2375 msi_free(deformated);
2376 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002377
2378 return ERROR_SUCCESS;
2379}
2380
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002381static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00002382{
2383 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002384 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002385 static const WCHAR ExecSeqQuery[] =
2386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002387 '`','R','e','g','i','s','t','r','y','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00002388
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002389 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002390 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002391 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00002392
Aric Stewartd2c395a2004-07-06 18:48:15 +00002393 /* increment progress bar each time action data is sent */
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002394 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002395
Aric Stewart92ef78e2005-06-21 20:21:18 +00002396 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002397
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002398 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002399 return rc;
2400}
2401
Hans Leidekker342f8662010-02-25 15:17:11 +01002402static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2403{
2404 LONG res;
2405 HKEY hkey;
2406 DWORD num_subkeys, num_values;
2407
2408 if (delete_key)
2409 {
2410 if ((res = RegDeleteTreeW( hkey_root, key )))
2411 {
2412 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2413 }
2414 return;
2415 }
2416
2417 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2418 {
2419 if ((res = RegDeleteValueW( hkey, value )))
2420 {
2421 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2422 }
2423 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2424 NULL, NULL, NULL, NULL );
2425 RegCloseKey( hkey );
2426
2427 if (!res && !num_subkeys && !num_values)
2428 {
2429 TRACE("Removing empty key %s\n", debugstr_w(key));
2430 RegDeleteKeyW( hkey_root, key );
2431 }
2432 return;
2433 }
2434 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2435}
2436
2437
2438static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2439{
2440 MSIPACKAGE *package = param;
2441 LPCWSTR component, name, key_str, root_key_str;
2442 LPWSTR deformated_key, deformated_name, ui_key_str;
2443 MSICOMPONENT *comp;
2444 MSIRECORD *uirow;
2445 BOOL delete_key = FALSE;
2446 HKEY hkey_root;
2447 UINT size;
2448 INT root;
2449
2450 ui_progress( package, 2, 0, 0, 0 );
2451
2452 component = MSI_RecordGetString( row, 6 );
2453 comp = get_loaded_component( package, component );
2454 if (!comp)
2455 return ERROR_SUCCESS;
2456
2457 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2458 {
2459 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2460 comp->Action = comp->Installed;
2461 return ERROR_SUCCESS;
2462 }
2463 comp->Action = INSTALLSTATE_ABSENT;
2464
2465 name = MSI_RecordGetString( row, 4 );
2466 if (MSI_RecordIsNull( row, 5 ) && name )
2467 {
2468 if (name[0] == '+' && !name[1])
2469 return ERROR_SUCCESS;
2470 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2471 {
2472 delete_key = TRUE;
2473 name = NULL;
2474 }
2475 }
2476
2477 root = MSI_RecordGetInteger( row, 2 );
2478 key_str = MSI_RecordGetString( row, 3 );
2479
2480 root_key_str = get_root_key( package, root, &hkey_root );
2481 if (!root_key_str)
2482 return ERROR_SUCCESS;
2483
2484 deformat_string( package, key_str, &deformated_key );
2485 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2486 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2487 strcpyW( ui_key_str, root_key_str );
2488 strcatW( ui_key_str, deformated_key );
2489
2490 deformat_string( package, name, &deformated_name );
2491
2492 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2493 msi_free( deformated_key );
2494
2495 uirow = MSI_CreateRecord( 2 );
2496 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2497 MSI_RecordSetStringW( uirow, 2, deformated_name );
2498
2499 ui_actiondata( package, szRemoveRegistryValues, uirow );
2500 msiobj_release( &uirow->hdr );
2501
2502 msi_free( ui_key_str );
2503 msi_free( deformated_name );
2504 return ERROR_SUCCESS;
2505}
2506
2507static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2508{
2509 MSIPACKAGE *package = param;
2510 LPCWSTR component, name, key_str, root_key_str;
2511 LPWSTR deformated_key, deformated_name, ui_key_str;
2512 MSICOMPONENT *comp;
2513 MSIRECORD *uirow;
2514 BOOL delete_key = FALSE;
2515 HKEY hkey_root;
2516 UINT size;
2517 INT root;
2518
2519 ui_progress( package, 2, 0, 0, 0 );
2520
2521 component = MSI_RecordGetString( row, 5 );
2522 comp = get_loaded_component( package, component );
2523 if (!comp)
2524 return ERROR_SUCCESS;
2525
2526 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2527 {
2528 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2529 comp->Action = comp->Installed;
2530 return ERROR_SUCCESS;
2531 }
2532 comp->Action = INSTALLSTATE_LOCAL;
2533
2534 if ((name = MSI_RecordGetString( row, 4 )))
2535 {
2536 if (name[0] == '-' && !name[1])
2537 {
2538 delete_key = TRUE;
2539 name = NULL;
2540 }
2541 }
2542
2543 root = MSI_RecordGetInteger( row, 2 );
2544 key_str = MSI_RecordGetString( row, 3 );
2545
2546 root_key_str = get_root_key( package, root, &hkey_root );
2547 if (!root_key_str)
2548 return ERROR_SUCCESS;
2549
2550 deformat_string( package, key_str, &deformated_key );
2551 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2552 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2553 strcpyW( ui_key_str, root_key_str );
2554 strcatW( ui_key_str, deformated_key );
2555
2556 deformat_string( package, name, &deformated_name );
2557
2558 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2559 msi_free( deformated_key );
2560
2561 uirow = MSI_CreateRecord( 2 );
2562 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2563 MSI_RecordSetStringW( uirow, 2, deformated_name );
2564
2565 ui_actiondata( package, szRemoveRegistryValues, uirow );
2566 msiobj_release( &uirow->hdr );
2567
2568 msi_free( ui_key_str );
2569 msi_free( deformated_name );
2570 return ERROR_SUCCESS;
2571}
2572
2573static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2574{
2575 UINT rc;
2576 MSIQUERY *view;
2577 static const WCHAR registry_query[] =
2578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2579 '`','R','e','g','i','s','t','r','y','`',0 };
2580 static const WCHAR remove_registry_query[] =
2581 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2582 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2583
2584 /* increment progress bar each time action data is sent */
2585 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2586
2587 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2588 if (rc == ERROR_SUCCESS)
2589 {
2590 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2591 msiobj_release( &view->hdr );
2592 if (rc != ERROR_SUCCESS)
2593 return rc;
2594 }
2595
2596 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2597 if (rc == ERROR_SUCCESS)
2598 {
2599 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2600 msiobj_release( &view->hdr );
2601 if (rc != ERROR_SUCCESS)
2602 return rc;
2603 }
2604
2605 return ERROR_SUCCESS;
2606}
2607
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002608static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002609{
Aric Stewart9cd707d2005-05-27 19:24:22 +00002610 package->script->CurrentlyScripting = TRUE;
2611
Aric Stewart7d3e5972004-07-04 00:36:58 +00002612 return ERROR_SUCCESS;
2613}
2614
Aric Stewartae1aa322004-12-27 19:02:59 +00002615
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002616static UINT ACTION_InstallValidate(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002617{
Mike McCormack38d67a42005-08-22 09:15:23 +00002618 MSICOMPONENT *comp;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002619 DWORD progress = 0;
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002620 DWORD total = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002621 static const WCHAR q1[]=
2622 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002623 '`','R','e','g','i','s','t','r','y','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002624 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002625 MSIQUERY * view;
Mike McCormack1da28582005-08-22 14:09:17 +00002626 MSIFEATURE *feature;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002627 MSIFILE *file;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002628
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002629 TRACE("InstallValidate\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002630
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002631 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002632 if (rc == ERROR_SUCCESS)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002633 {
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002634 MSI_IterateRecords( view, &progress, NULL, package );
2635 msiobj_release( &view->hdr );
2636 total += progress * REG_PROGRESS_VALUE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002637 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002638
Mike McCormack38d67a42005-08-22 09:15:23 +00002639 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Mike McCormack38d67a42005-08-22 09:15:23 +00002640 total += COMPONENT_PROGRESS_VALUE;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002641
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002642 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002643 total += file->FileSize;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002644
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002645 ui_progress(package,0,total,0,0);
Aric Stewart7d3e5972004-07-04 00:36:58 +00002646
Mike McCormack1da28582005-08-22 14:09:17 +00002647 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002648 {
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002649 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2650 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2651 feature->ActionRequest);
2652 }
2653
Aric Stewart7d3e5972004-07-04 00:36:58 +00002654 return ERROR_SUCCESS;
2655}
2656
Aric Stewartc79f4e22005-06-22 18:03:08 +00002657static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2658{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01002659 MSIPACKAGE* package = param;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002660 LPCWSTR cond = NULL;
2661 LPCWSTR message = NULL;
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002662 UINT r;
2663
Aric Stewartc79f4e22005-06-22 18:03:08 +00002664 static const WCHAR title[]=
2665 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2666
2667 cond = MSI_RecordGetString(row,1);
2668
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002669 r = MSI_EvaluateConditionW(package,cond);
2670 if (r == MSICONDITION_FALSE)
Aric Stewartc79f4e22005-06-22 18:03:08 +00002671 {
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002672 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2673 {
2674 LPWSTR deformated;
2675 message = MSI_RecordGetString(row,2);
2676 deformat_string(package,message,&deformated);
2677 MessageBoxW(NULL,deformated,title,MB_OK);
2678 msi_free(deformated);
2679 }
2680
2681 return ERROR_INSTALL_FAILURE;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002682 }
2683
2684 return ERROR_SUCCESS;
2685}
2686
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002687static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
Aric Stewart5b936ca2004-07-06 18:47:09 +00002688{
2689 UINT rc;
Mike McCormackf3c8b832004-07-19 19:35:05 +00002690 MSIQUERY * view = NULL;
Aric Stewart8e233e92005-03-01 11:45:19 +00002691 static const WCHAR ExecSeqQuery[] =
2692 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002693 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002694
Aric Stewart5b936ca2004-07-06 18:47:09 +00002695 TRACE("Checking launch conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002696
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002697 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart5b936ca2004-07-06 18:47:09 +00002698 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002699 return ERROR_SUCCESS;
Aric Stewart5b936ca2004-07-06 18:47:09 +00002700
Aric Stewartc79f4e22005-06-22 18:03:08 +00002701 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002702 msiobj_release(&view->hdr);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002703
Aric Stewart5b936ca2004-07-06 18:47:09 +00002704 return rc;
2705}
Aric Stewart7d3e5972004-07-04 00:36:58 +00002706
Mike McCormack38d67a42005-08-22 09:15:23 +00002707static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
Aric Stewartb942e182004-07-06 18:50:02 +00002708{
Aric Stewartb942e182004-07-06 18:50:02 +00002709
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002710 if (!cmp->KeyPath)
James Hawkins8cedb212007-03-29 02:38:57 -05002711 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002712
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002713 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
Aric Stewartb942e182004-07-06 18:50:02 +00002714 {
Aric Stewart6269f002005-01-17 13:40:39 +00002715 MSIRECORD * row = 0;
Mike McCormack0b352c72005-06-02 10:29:57 +00002716 UINT root,len;
Aric Stewart09b0aba2005-06-09 20:30:59 +00002717 LPWSTR deformated,buffer,deformated_name;
2718 LPCWSTR key,name;
Aric Stewart8e233e92005-03-01 11:45:19 +00002719 static const WCHAR ExecSeqQuery[] =
2720 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002721 '`','R','e','g','i','s','t','r','y','`',' ',
2722 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2723 ' ','=',' ' ,'\'','%','s','\'',0 };
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002724 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00002725 static const WCHAR fmt2[]=
2726 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
Aric Stewart6269f002005-01-17 13:40:39 +00002727
Mike McCormack0b352c72005-06-02 10:29:57 +00002728 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2729 if (!row)
Aric Stewart6269f002005-01-17 13:40:39 +00002730 return NULL;
2731
Aric Stewart6269f002005-01-17 13:40:39 +00002732 root = MSI_RecordGetInteger(row,2);
Aric Stewart09b0aba2005-06-09 20:30:59 +00002733 key = MSI_RecordGetString(row, 3);
2734 name = MSI_RecordGetString(row, 4);
Aric Stewart6269f002005-01-17 13:40:39 +00002735 deformat_string(package, key , &deformated);
2736 deformat_string(package, name, &deformated_name);
2737
Ulrich Czekallae15e5172005-03-08 16:44:51 +00002738 len = strlenW(deformated) + 6;
Aric Stewart6269f002005-01-17 13:40:39 +00002739 if (deformated_name)
2740 len+=strlenW(deformated_name);
2741
Mike McCormackee034ba2005-09-20 11:59:14 +00002742 buffer = msi_alloc( len *sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00002743
2744 if (deformated_name)
2745 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2746 else
2747 sprintfW(buffer,fmt,root,deformated);
2748
Mike McCormackee034ba2005-09-20 11:59:14 +00002749 msi_free(deformated);
2750 msi_free(deformated_name);
Aric Stewart6269f002005-01-17 13:40:39 +00002751 msiobj_release(&row->hdr);
Aric Stewart6269f002005-01-17 13:40:39 +00002752
2753 return buffer;
2754 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002755 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewart6269f002005-01-17 13:40:39 +00002756 {
2757 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
Aric Stewartfa384f62004-12-22 18:46:17 +00002758 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002759 }
2760 else
2761 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002762 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
Aric Stewartfcb20c52004-07-06 18:51:16 +00002763
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002764 if (file)
2765 return strdupW( file->TargetPath );
Aric Stewartb942e182004-07-06 18:50:02 +00002766 }
Aric Stewartfa384f62004-12-22 18:46:17 +00002767 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002768}
2769
Stefan Huehnerac6f5622005-06-20 14:18:03 +00002770static HKEY openSharedDLLsKey(void)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002771{
2772 HKEY hkey=0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002773 static const WCHAR path[] =
2774 {'S','o','f','t','w','a','r','e','\\',
2775 'M','i','c','r','o','s','o','f','t','\\',
2776 'W','i','n','d','o','w','s','\\',
2777 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2778 'S','h','a','r','e','d','D','L','L','s',0};
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002779
2780 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2781 return hkey;
2782}
2783
2784static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2785{
2786 HKEY hkey;
2787 DWORD count=0;
2788 DWORD type;
2789 DWORD sz = sizeof(count);
2790 DWORD rc;
2791
2792 hkey = openSharedDLLsKey();
2793 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2794 if (rc != ERROR_SUCCESS)
2795 count = 0;
2796 RegCloseKey(hkey);
2797 return count;
2798}
2799
2800static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2801{
2802 HKEY hkey;
2803
2804 hkey = openSharedDLLsKey();
2805 if (count > 0)
Mike McCormack4db02cd2005-09-15 14:58:38 +00002806 msi_reg_set_val_dword( hkey, path, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002807 else
2808 RegDeleteValueW(hkey,path);
2809 RegCloseKey(hkey);
2810 return count;
2811}
2812
2813/*
2814 * Return TRUE if the count should be written out and FALSE if not
2815 */
Mike McCormack38d67a42005-08-22 09:15:23 +00002816static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002817{
Mike McCormack1da28582005-08-22 14:09:17 +00002818 MSIFEATURE *feature;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002819 INT count = 0;
2820 BOOL write = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002821
2822 /* only refcount DLLs */
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002823 if (comp->KeyPath == NULL ||
Mike McCormack38d67a42005-08-22 09:15:23 +00002824 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2825 comp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002826 write = FALSE;
2827 else
2828 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002829 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002830 write = (count > 0);
2831
Mike McCormack38d67a42005-08-22 09:15:23 +00002832 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002833 write = TRUE;
2834 }
2835
2836 /* increment counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002837 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002838 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002839 ComponentList *cl;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002840
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01002841 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002842 continue;
2843
Mike McCormack1da28582005-08-22 14:09:17 +00002844 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002845 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002846 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002847 count++;
2848 }
2849 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002850
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002851 /* decrement counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002852 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002853 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002854 ComponentList *cl;
2855
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01002856 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002857 continue;
2858
Mike McCormack1da28582005-08-22 14:09:17 +00002859 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002860 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002861 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002862 count--;
2863 }
2864 }
2865
2866 /* ref count all the files in the component */
2867 if (write)
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002868 {
2869 MSIFILE *file;
2870
2871 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002872 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002873 if (file->Component == comp)
2874 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002875 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002876 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002877
Austin English5644f052008-04-07 14:44:23 -05002878 /* add a count for permanent */
Mike McCormack38d67a42005-08-22 09:15:23 +00002879 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002880 count ++;
2881
Mike McCormack38d67a42005-08-22 09:15:23 +00002882 comp->RefCount = count;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002883
2884 if (write)
Mike McCormack38d67a42005-08-22 09:15:23 +00002885 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002886}
2887
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002888static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
Aric Stewartb942e182004-07-06 18:50:02 +00002889{
Aric Stewart68b07492005-01-25 11:05:37 +00002890 WCHAR squished_pc[GUID_SIZE];
2891 WCHAR squished_cc[GUID_SIZE];
Aric Stewartb942e182004-07-06 18:50:02 +00002892 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00002893 MSICOMPONENT *comp;
James Hawkins4aa3a992008-06-18 00:49:42 -05002894 HKEY hkey;
Aric Stewartb942e182004-07-06 18:50:02 +00002895
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002896 TRACE("\n");
2897
Aric Stewartadaef112005-07-07 20:27:06 +00002898 squash_guid(package->ProductCode,squished_pc);
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002899 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
Mike McCormack38d67a42005-08-22 09:15:23 +00002900
2901 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewartb942e182004-07-06 18:50:02 +00002902 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002903 MSIRECORD * uirow;
2904
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002905 ui_progress(package,2,0,0,0);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002906 if (!comp->ComponentId)
2907 continue;
Aric Stewartb942e182004-07-06 18:50:02 +00002908
Mike McCormackfe8cd382006-03-09 14:21:37 +09002909 squash_guid(comp->ComponentId,squished_cc);
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002910
Mike McCormackfe8cd382006-03-09 14:21:37 +09002911 msi_free(comp->FullKeypath);
2912 comp->FullKeypath = resolve_keypath( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002913
Mike McCormackfe8cd382006-03-09 14:21:37 +09002914 ACTION_RefCountComponent( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002915
Mike McCormackfe8cd382006-03-09 14:21:37 +09002916 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
Mike McCormack38d67a42005-08-22 09:15:23 +00002917 debugstr_w(comp->Component),
Aric Stewartc5a14432005-05-18 17:46:12 +00002918 debugstr_w(squished_cc),
Mike McCormackfe8cd382006-03-09 14:21:37 +09002919 debugstr_w(comp->FullKeypath),
Mike McCormack38d67a42005-08-22 09:15:23 +00002920 comp->RefCount);
James Hawkins96dd6ce2008-08-21 02:14:26 -05002921
Hans Leidekker598c5422010-02-16 11:44:47 +01002922 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
2923 comp->ActionRequest == INSTALLSTATE_SOURCE)
Mike McCormackfe8cd382006-03-09 14:21:37 +09002924 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002925 if (!comp->FullKeypath)
2926 continue;
2927
James Hawkins288af812008-06-18 00:51:13 -05002928 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
James Hawkinsb198f4f2008-12-09 00:21:00 -06002929 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2930 &hkey, TRUE);
James Hawkins288af812008-06-18 00:51:13 -05002931 else
James Hawkinsb198f4f2008-12-09 00:21:00 -06002932 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2933 &hkey, TRUE);
James Hawkins288af812008-06-18 00:51:13 -05002934
James Hawkins4aa3a992008-06-18 00:49:42 -05002935 if (rc != ERROR_SUCCESS)
2936 continue;
Mike McCormackfe8cd382006-03-09 14:21:37 +09002937
2938 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartfa384f62004-12-22 18:46:17 +00002939 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002940 static const WCHAR szPermKey[] =
2941 { '0','0','0','0','0','0','0','0','0','0','0','0',
2942 '0','0','0','0','0','0','0','0','0','0','0','0',
2943 '0','0','0','0','0','0','0','0',0 };
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002944
James Hawkins4aa3a992008-06-18 00:49:42 -05002945 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002946 }
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002947
James Hawkins96dd6ce2008-08-21 02:14:26 -05002948 if (comp->Action == INSTALLSTATE_LOCAL)
2949 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2950 else
2951 {
2952 MSIFILE *file;
2953 MSIRECORD *row;
2954 LPWSTR ptr, ptr2;
2955 WCHAR source[MAX_PATH];
2956 WCHAR base[MAX_PATH];
James Hawkinsd15fddf2008-10-06 22:26:20 -05002957 LPWSTR sourcepath;
James Hawkins96dd6ce2008-08-21 02:14:26 -05002958
2959 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
2960 static const WCHAR query[] = {
2961 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2962 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2963 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2964 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2965 '`','D','i','s','k','I','d','`',0};
2966
2967 file = get_loaded_file(package, comp->KeyPath);
2968 if (!file)
2969 continue;
2970
2971 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2972 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2973 ptr2 = strrchrW(source, '\\') + 1;
2974 msiobj_release(&row->hdr);
2975
2976 lstrcpyW(base, package->PackagePath);
2977 ptr = strrchrW(base, '\\');
2978 *(ptr + 1) = '\0';
2979
James Hawkinsd15fddf2008-10-06 22:26:20 -05002980 sourcepath = resolve_file_source(package, file);
2981 ptr = sourcepath + lstrlenW(base);
James Hawkins96dd6ce2008-08-21 02:14:26 -05002982 lstrcpyW(ptr2, ptr);
James Hawkinsd15fddf2008-10-06 22:26:20 -05002983 msi_free(sourcepath);
James Hawkins96dd6ce2008-08-21 02:14:26 -05002984
2985 msi_reg_set_val_str(hkey, squished_pc, source);
2986 }
James Hawkins4aa3a992008-06-18 00:49:42 -05002987 RegCloseKey(hkey);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002988 }
Hans Leidekker598c5422010-02-16 11:44:47 +01002989 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
James Hawkins288af812008-06-18 00:51:13 -05002990 {
2991 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
James Hawkinsa9e02902008-12-09 00:21:19 -06002992 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
James Hawkins288af812008-06-18 00:51:13 -05002993 else
James Hawkinsa9e02902008-12-09 00:21:19 -06002994 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
James Hawkins288af812008-06-18 00:51:13 -05002995 }
Hans Leidekker27e90272010-03-23 11:46:24 +01002996 comp->Action = comp->ActionRequest;
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002997
2998 /* UI stuff */
2999 uirow = MSI_CreateRecord(3);
3000 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3001 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3002 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3003 ui_actiondata(package,szProcessComponents,uirow);
3004 msiobj_release( &uirow->hdr );
3005 }
James Hawkins4aa3a992008-06-18 00:49:42 -05003006
3007 return ERROR_SUCCESS;
Aric Stewartb942e182004-07-06 18:50:02 +00003008}
3009
Aric Stewart6e821732005-03-30 10:19:08 +00003010typedef struct {
3011 CLSID clsid;
3012 LPWSTR source;
3013
3014 LPWSTR path;
3015 ITypeLib *ptLib;
3016} typelib_struct;
3017
Mike McCormackf9acfe62005-06-07 20:29:51 +00003018static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
Aric Stewart6e821732005-03-30 10:19:08 +00003019 LPWSTR lpszName, LONG_PTR lParam)
3020{
3021 TLIBATTR *attr;
3022 typelib_struct *tl_struct = (typelib_struct*) lParam;
3023 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3024 int sz;
3025 HRESULT res;
3026
3027 if (!IS_INTRESOURCE(lpszName))
3028 {
3029 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3030 return TRUE;
3031 }
3032
3033 sz = strlenW(tl_struct->source)+4;
3034 sz *= sizeof(WCHAR);
3035
Mike McCormack2acf8002006-05-25 11:41:39 +09003036 if ((INT_PTR)lpszName == 1)
Aric Stewartca8c4e42005-06-02 15:13:57 +00003037 tl_struct->path = strdupW(tl_struct->source);
3038 else
3039 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003040 tl_struct->path = msi_alloc(sz);
Aric Stewartca8c4e42005-06-02 15:13:57 +00003041 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3042 }
Aric Stewart6e821732005-03-30 10:19:08 +00003043
3044 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3045 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
Michael Stefaniuc704ebf22008-10-08 01:33:34 +02003046 if (FAILED(res))
Aric Stewart6e821732005-03-30 10:19:08 +00003047 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003048 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003049 tl_struct->path = NULL;
3050
3051 return TRUE;
3052 }
3053
3054 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3055 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3056 {
3057 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3058 return FALSE;
3059 }
3060
Mike McCormackee034ba2005-09-20 11:59:14 +00003061 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003062 tl_struct->path = NULL;
3063
3064 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3065 ITypeLib_Release(tl_struct->ptLib);
3066
3067 return TRUE;
3068}
3069
Aric Stewart234dc4b2005-06-22 18:27:34 +00003070static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3071{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003072 MSIPACKAGE* package = param;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003073 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00003074 MSICOMPONENT *comp;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003075 MSIFILE *file;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003076 typelib_struct tl_struct;
James Hawkins469e4a52008-07-28 22:19:47 -05003077 ITypeLib *tlib;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003078 HMODULE module;
James Hawkins469e4a52008-07-28 22:19:47 -05003079 HRESULT hr;
3080
Aric Stewart234dc4b2005-06-22 18:27:34 +00003081 component = MSI_RecordGetString(row,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00003082 comp = get_loaded_component(package,component);
3083 if (!comp)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003084 return ERROR_SUCCESS;
3085
Hans Leidekker598c5422010-02-16 11:44:47 +01003086 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003087 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003088 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003089 comp->Action = comp->Installed;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003090 return ERROR_SUCCESS;
3091 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003092 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003093
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003094 file = get_loaded_file( package, comp->KeyPath );
3095 if (!file)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003096 return ERROR_SUCCESS;
3097
Hans Leidekker54391a12010-02-16 11:44:34 +01003098 ui_actiondata( package, szRegisterTypeLibraries, row );
3099
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003100 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
Mike McCormack51c66182005-10-27 12:36:12 +00003101 if (module)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003102 {
Mike McCormack51c66182005-10-27 12:36:12 +00003103 LPCWSTR guid;
3104 guid = MSI_RecordGetString(row,1);
3105 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003106 tl_struct.source = strdupW( file->TargetPath );
Aric Stewart234dc4b2005-06-22 18:27:34 +00003107 tl_struct.path = NULL;
3108
3109 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3110 (LONG_PTR)&tl_struct);
3111
Mike McCormack51c66182005-10-27 12:36:12 +00003112 if (tl_struct.path)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003113 {
3114 LPWSTR help = NULL;
3115 LPCWSTR helpid;
3116 HRESULT res;
3117
3118 helpid = MSI_RecordGetString(row,6);
3119
3120 if (helpid)
James Hawkins8cedb212007-03-29 02:38:57 -05003121 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003122 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
Mike McCormackee034ba2005-09-20 11:59:14 +00003123 msi_free(help);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003124
Michael Stefaniuc704ebf22008-10-08 01:33:34 +02003125 if (FAILED(res))
Aric Stewart234dc4b2005-06-22 18:27:34 +00003126 ERR("Failed to register type library %s\n",
3127 debugstr_w(tl_struct.path));
3128 else
Aric Stewart234dc4b2005-06-22 18:27:34 +00003129 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
Aric Stewart234dc4b2005-06-22 18:27:34 +00003130
3131 ITypeLib_Release(tl_struct.ptLib);
Mike McCormackee034ba2005-09-20 11:59:14 +00003132 msi_free(tl_struct.path);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003133 }
3134 else
3135 ERR("Failed to load type library %s\n",
3136 debugstr_w(tl_struct.source));
3137
3138 FreeLibrary(module);
Mike McCormackee034ba2005-09-20 11:59:14 +00003139 msi_free(tl_struct.source);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003140 }
3141 else
James Hawkins469e4a52008-07-28 22:19:47 -05003142 {
3143 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3144 if (FAILED(hr))
3145 {
3146 ERR("Failed to load type library: %08x\n", hr);
Hans Leidekker82d50fa2010-02-12 10:33:00 +01003147 return ERROR_INSTALL_FAILURE;
James Hawkins469e4a52008-07-28 22:19:47 -05003148 }
3149
3150 ITypeLib_Release(tlib);
3151 }
Aric Stewart234dc4b2005-06-22 18:27:34 +00003152
3153 return ERROR_SUCCESS;
3154}
3155
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003156static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
Aric Stewartfcb20c52004-07-06 18:51:16 +00003157{
3158 /*
Mike McCormackc90c7812004-07-09 22:58:27 +00003159 * OK this is a bit confusing.. I am given a _Component key and I believe
Aric Stewartfcb20c52004-07-06 18:51:16 +00003160 * that the file that is being registered as a type library is the "key file
Mike McCormackc90c7812004-07-09 22:58:27 +00003161 * of that component" which I interpret to mean "The file in the KeyPath of
3162 * that component".
Aric Stewartfcb20c52004-07-06 18:51:16 +00003163 */
3164 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003165 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003166 static const WCHAR Query[] =
3167 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003168 '`','T','y','p','e','L','i','b','`',0};
Aric Stewartfcb20c52004-07-06 18:51:16 +00003169
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003170 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003171 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00003172 return ERROR_SUCCESS;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003173
Aric Stewart234dc4b2005-06-22 18:27:34 +00003174 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003175 msiobj_release(&view->hdr);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003176 return rc;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003177}
3178
Hans Leidekker98761032010-02-12 10:32:35 +01003179static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3180{
3181 MSIPACKAGE *package = param;
3182 LPCWSTR component, guid;
3183 MSICOMPONENT *comp;
3184 GUID libid;
3185 UINT version;
3186 LCID language;
3187 SYSKIND syskind;
3188 HRESULT hr;
3189
3190 component = MSI_RecordGetString( row, 3 );
3191 comp = get_loaded_component( package, component );
3192 if (!comp)
3193 return ERROR_SUCCESS;
3194
Hans Leidekker598c5422010-02-16 11:44:47 +01003195 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
Hans Leidekker98761032010-02-12 10:32:35 +01003196 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003197 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
Hans Leidekker98761032010-02-12 10:32:35 +01003198 comp->Action = comp->Installed;
3199 return ERROR_SUCCESS;
3200 }
3201 comp->Action = INSTALLSTATE_ABSENT;
3202
Hans Leidekker54391a12010-02-16 11:44:34 +01003203 ui_actiondata( package, szUnregisterTypeLibraries, row );
3204
Hans Leidekker98761032010-02-12 10:32:35 +01003205 guid = MSI_RecordGetString( row, 1 );
3206 CLSIDFromString( (LPWSTR)guid, &libid );
3207 version = MSI_RecordGetInteger( row, 4 );
3208 language = MSI_RecordGetInteger( row, 2 );
3209
3210#ifdef _WIN64
3211 syskind = SYS_WIN64;
3212#else
3213 syskind = SYS_WIN32;
3214#endif
3215
3216 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3217 if (FAILED(hr))
3218 {
3219 WARN("Failed to unregister typelib: %08x\n", hr);
3220 }
3221
3222 return ERROR_SUCCESS;
3223}
3224
3225static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3226{
3227 UINT rc;
3228 MSIQUERY *view;
3229 static const WCHAR query[] =
3230 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3231 '`','T','y','p','e','L','i','b','`',0};
3232
3233 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3234 if (rc != ERROR_SUCCESS)
3235 return ERROR_SUCCESS;
3236
3237 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3238 msiobj_release( &view->hdr );
3239 return rc;
3240}
3241
Hans Leidekker2276c292010-02-15 10:20:01 +01003242static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3243{
3244 static const WCHAR szlnk[] = {'.','l','n','k',0};
3245 LPCWSTR directory, extension;
3246 LPWSTR link_folder, link_file, filename;
3247
3248 directory = MSI_RecordGetString( row, 2 );
3249 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3250
3251 /* may be needed because of a bug somewhere else */
3252 create_full_pathW( link_folder );
3253
3254 filename = msi_dup_record_field( row, 3 );
3255 reduce_to_longfilename( filename );
3256
3257 extension = strchrW( filename, '.' );
3258 if (!extension || strcmpiW( extension, szlnk ))
3259 {
3260 int len = strlenW( filename );
3261 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3262 memcpy( filename + len, szlnk, sizeof(szlnk) );
3263 }
3264 link_file = build_directory_name( 2, link_folder, filename );
3265 msi_free( link_folder );
3266 msi_free( filename );
3267
3268 return link_file;
3269}
3270
Aric Stewart9adacf62005-06-24 11:58:21 +00003271static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003272{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003273 MSIPACKAGE *package = param;
Hans Leidekker2276c292010-02-15 10:20:01 +01003274 LPWSTR link_file, deformated, path;
3275 LPCWSTR component, target;
Mike McCormack38d67a42005-08-22 09:15:23 +00003276 MSICOMPONENT *comp;
Mike McCormack20c57462006-05-24 17:41:04 +09003277 IShellLinkW *sl = NULL;
3278 IPersistFile *pf = NULL;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003279 HRESULT res;
3280
Hans Leidekker2276c292010-02-15 10:20:01 +01003281 component = MSI_RecordGetString(row, 4);
3282 comp = get_loaded_component(package, component);
Mike McCormack38d67a42005-08-22 09:15:23 +00003283 if (!comp)
Aric Stewart9adacf62005-06-24 11:58:21 +00003284 return ERROR_SUCCESS;
3285
Hans Leidekker598c5422010-02-16 11:44:47 +01003286 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart9adacf62005-06-24 11:58:21 +00003287 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003288 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003289 comp->Action = comp->Installed;
Aric Stewart9adacf62005-06-24 11:58:21 +00003290 return ERROR_SUCCESS;
3291 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003292 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart9adacf62005-06-24 11:58:21 +00003293
3294 ui_actiondata(package,szCreateShortcuts,row);
3295
3296 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3297 &IID_IShellLinkW, (LPVOID *) &sl );
3298
Mike McCormack20c57462006-05-24 17:41:04 +09003299 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003300 {
Mike McCormack20c57462006-05-24 17:41:04 +09003301 ERR("CLSID_ShellLink not available\n");
3302 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003303 }
3304
3305 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
Mike McCormack20c57462006-05-24 17:41:04 +09003306 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003307 {
Mike McCormack20c57462006-05-24 17:41:04 +09003308 ERR("QueryInterface(IID_IPersistFile) failed\n");
3309 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003310 }
3311
Hans Leidekker2276c292010-02-15 10:20:01 +01003312 target = MSI_RecordGetString(row, 5);
3313 if (strchrW(target, '['))
Robert Shearman4ac85672006-02-22 16:31:00 +00003314 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003315 deformat_string(package, target, &deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003316 IShellLinkW_SetPath(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003317 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003318 }
3319 else
3320 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003321 FIXME("poorly handled shortcut format, advertised shortcut\n");
Mike McCormack566c69e2005-09-22 10:49:17 +00003322 IShellLinkW_SetPath(sl,comp->FullKeypath);
Aric Stewart9adacf62005-06-24 11:58:21 +00003323 }
3324
3325 if (!MSI_RecordIsNull(row,6))
3326 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003327 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3328 deformat_string(package, arguments, &deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003329 IShellLinkW_SetArguments(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003330 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003331 }
3332
3333 if (!MSI_RecordIsNull(row,7))
3334 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003335 LPCWSTR description = MSI_RecordGetString(row, 7);
3336 IShellLinkW_SetDescription(sl, description);
Aric Stewart9adacf62005-06-24 11:58:21 +00003337 }
3338
3339 if (!MSI_RecordIsNull(row,8))
3340 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3341
3342 if (!MSI_RecordIsNull(row,9))
3343 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003344 INT index;
Hans Leidekker2276c292010-02-15 10:20:01 +01003345 LPCWSTR icon = MSI_RecordGetString(row, 9);
Aric Stewart9adacf62005-06-24 11:58:21 +00003346
Hans Leidekker2276c292010-02-15 10:20:01 +01003347 path = build_icon_path(package, icon);
Aric Stewart9adacf62005-06-24 11:58:21 +00003348 index = MSI_RecordGetInteger(row,10);
3349
Robert Shearmanab378802006-08-03 20:24:10 +01003350 /* no value means 0 */
3351 if (index == MSI_NULL_INTEGER)
3352 index = 0;
3353
Hans Leidekker2276c292010-02-15 10:20:01 +01003354 IShellLinkW_SetIconLocation(sl, path, index);
3355 msi_free(path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003356 }
3357
3358 if (!MSI_RecordIsNull(row,11))
3359 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3360
3361 if (!MSI_RecordIsNull(row,12))
3362 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003363 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3364 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3365 if (path)
3366 IShellLinkW_SetWorkingDirectory(sl, path);
3367 msi_free(path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003368 }
3369
Hans Leidekker2276c292010-02-15 10:20:01 +01003370 link_file = get_link_file(package, row);
Aric Stewart9adacf62005-06-24 11:58:21 +00003371
Hans Leidekker2276c292010-02-15 10:20:01 +01003372 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3373 IPersistFile_Save(pf, link_file, FALSE);
3374
3375 msi_free(link_file);
Aric Stewart9adacf62005-06-24 11:58:21 +00003376
Mike McCormack20c57462006-05-24 17:41:04 +09003377err:
3378 if (pf)
3379 IPersistFile_Release( pf );
3380 if (sl)
3381 IShellLinkW_Release( sl );
Aric Stewart9adacf62005-06-24 11:58:21 +00003382
3383 return ERROR_SUCCESS;
3384}
3385
3386static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3387{
3388 UINT rc;
3389 HRESULT res;
3390 MSIQUERY * view;
3391 static const WCHAR Query[] =
3392 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3393 '`','S','h','o','r','t','c','u','t','`',0};
3394
Aric Stewart9adacf62005-06-24 11:58:21 +00003395 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3396 if (rc != ERROR_SUCCESS)
3397 return ERROR_SUCCESS;
3398
Aric Stewart2cf222f2004-07-06 19:00:23 +00003399 res = CoInitialize( NULL );
Aric Stewart2cf222f2004-07-06 19:00:23 +00003400
Aric Stewart9adacf62005-06-24 11:58:21 +00003401 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003402 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003403
Hans Leidekkerdd1ca6c2009-09-10 10:10:33 +02003404 if (SUCCEEDED(res))
3405 CoUninitialize();
Aric Stewart2cf222f2004-07-06 19:00:23 +00003406
3407 return rc;
3408}
3409
Hans Leidekker2276c292010-02-15 10:20:01 +01003410static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3411{
3412 MSIPACKAGE *package = param;
3413 LPWSTR link_file;
3414 LPCWSTR component;
3415 MSICOMPONENT *comp;
3416
3417 component = MSI_RecordGetString( row, 4 );
3418 comp = get_loaded_component( package, component );
3419 if (!comp)
3420 return ERROR_SUCCESS;
3421
Hans Leidekker598c5422010-02-16 11:44:47 +01003422 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
Hans Leidekker2276c292010-02-15 10:20:01 +01003423 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003424 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
Hans Leidekker2276c292010-02-15 10:20:01 +01003425 comp->Action = comp->Installed;
3426 return ERROR_SUCCESS;
3427 }
3428 comp->Action = INSTALLSTATE_ABSENT;
3429
3430 ui_actiondata( package, szRemoveShortcuts, row );
3431
3432 link_file = get_link_file( package, row );
3433
3434 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3435 if (!DeleteFileW( link_file ))
3436 {
3437 WARN("Failed to remove shortcut file %u\n", GetLastError());
3438 }
3439 msi_free( link_file );
3440
3441 return ERROR_SUCCESS;
3442}
3443
3444static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3445{
3446 UINT rc;
3447 MSIQUERY *view;
3448 static const WCHAR query[] =
3449 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3450 '`','S','h','o','r','t','c','u','t','`',0};
3451
3452 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3453 if (rc != ERROR_SUCCESS)
3454 return ERROR_SUCCESS;
3455
3456 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3457 msiobj_release( &view->hdr );
3458
3459 return rc;
3460}
3461
James Hawkinsfac97bb2008-06-23 22:56:56 -05003462static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
Aric Stewart916ef942005-06-22 18:42:19 +00003463{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003464 MSIPACKAGE* package = param;
Aric Stewart916ef942005-06-22 18:42:19 +00003465 HANDLE the_file;
Mike McCormack75658d72005-09-22 10:33:57 +00003466 LPWSTR FilePath;
3467 LPCWSTR FileName;
Aric Stewart916ef942005-06-22 18:42:19 +00003468 CHAR buffer[1024];
3469 DWORD sz;
3470 UINT rc;
3471
3472 FileName = MSI_RecordGetString(row,1);
3473 if (!FileName)
3474 {
3475 ERR("Unable to get FileName\n");
3476 return ERROR_SUCCESS;
3477 }
3478
Mike McCormack75658d72005-09-22 10:33:57 +00003479 FilePath = build_icon_path(package,FileName);
Aric Stewart916ef942005-06-22 18:42:19 +00003480
3481 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3482
3483 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3484 FILE_ATTRIBUTE_NORMAL, NULL);
3485
3486 if (the_file == INVALID_HANDLE_VALUE)
3487 {
3488 ERR("Unable to create file %s\n",debugstr_w(FilePath));
Mike McCormackee034ba2005-09-20 11:59:14 +00003489 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003490 return ERROR_SUCCESS;
3491 }
3492
3493 do
3494 {
3495 DWORD write;
3496 sz = 1024;
3497 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3498 if (rc != ERROR_SUCCESS)
3499 {
3500 ERR("Failed to get stream\n");
3501 CloseHandle(the_file);
3502 DeleteFileW(FilePath);
3503 break;
3504 }
3505 WriteFile(the_file,buffer,sz,&write,NULL);
3506 } while (sz == 1024);
3507
Mike McCormackee034ba2005-09-20 11:59:14 +00003508 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003509 CloseHandle(the_file);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003510
Aric Stewart916ef942005-06-22 18:42:19 +00003511 return ERROR_SUCCESS;
3512}
Aric Stewart2cf222f2004-07-06 19:00:23 +00003513
James Hawkinsfac97bb2008-06-23 22:56:56 -05003514static UINT msi_publish_icons(MSIPACKAGE *package)
3515{
3516 UINT r;
3517 MSIQUERY *view;
3518
3519 static const WCHAR query[]= {
3520 'S','E','L','E','C','T',' ','*',' ',
3521 'F','R','O','M',' ','`','I','c','o','n','`',0};
3522
3523 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3524 if (r == ERROR_SUCCESS)
3525 {
3526 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3527 msiobj_release(&view->hdr);
3528 }
3529
3530 return ERROR_SUCCESS;
3531}
3532
James Hawkins2d4e4b62008-06-23 23:05:25 -05003533static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
James Hawkins68e60712008-06-23 22:57:36 -05003534{
3535 UINT r;
James Hawkins2d4e4b62008-06-23 23:05:25 -05003536 HKEY source;
James Hawkins68e60712008-06-23 22:57:36 -05003537 LPWSTR buffer;
3538 MSIMEDIADISK *disk;
3539 MSISOURCELISTINFO *info;
3540
James Hawkins2d4e4b62008-06-23 23:05:25 -05003541 r = RegCreateKeyW(hkey, szSourceList, &source);
3542 if (r != ERROR_SUCCESS)
3543 return r;
3544
3545 RegCloseKey(source);
James Hawkins68e60712008-06-23 22:57:36 -05003546
3547 buffer = strrchrW(package->PackagePath, '\\') + 1;
3548 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3549 package->Context, MSICODE_PRODUCT,
3550 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3551 if (r != ERROR_SUCCESS)
3552 return r;
3553
3554 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3555 package->Context, MSICODE_PRODUCT,
3556 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3557 if (r != ERROR_SUCCESS)
3558 return r;
3559
3560 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3561 package->Context, MSICODE_PRODUCT,
3562 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3563 if (r != ERROR_SUCCESS)
3564 return r;
3565
3566 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3567 {
3568 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3569 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3570 info->options, info->value);
3571 else
3572 MsiSourceListSetInfoW(package->ProductCode, NULL,
3573 info->context, info->options,
3574 info->property, info->value);
3575 }
3576
3577 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3578 {
3579 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3580 disk->context, disk->options,
3581 disk->disk_id, disk->volume_label, disk->disk_prompt);
3582 }
3583
3584 return ERROR_SUCCESS;
3585}
3586
James Hawkinsebeb5372008-06-23 22:59:41 -05003587static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3588{
3589 MSIHANDLE hdb, suminfo;
3590 WCHAR guids[MAX_PATH];
James Hawkinsdb2e8d22008-06-23 23:00:21 -05003591 WCHAR packcode[SQUISH_GUID_SIZE];
James Hawkinsebeb5372008-06-23 22:59:41 -05003592 LPWSTR buffer;
3593 LPWSTR ptr;
3594 DWORD langid;
3595 DWORD size;
3596 UINT r;
3597
3598 static const WCHAR szProductLanguage[] =
3599 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3600 static const WCHAR szARPProductIcon[] =
3601 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3602 static const WCHAR szProductVersion[] =
3603 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
James Hawkinsef640a62008-06-23 23:01:44 -05003604 static const WCHAR szAssignment[] =
3605 {'A','s','s','i','g','n','m','e','n','t',0};
3606 static const WCHAR szAdvertiseFlags[] =
3607 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3608 static const WCHAR szClients[] =
3609 {'C','l','i','e','n','t','s',0};
3610 static const WCHAR szColon[] = {':',0};
James Hawkinsebeb5372008-06-23 22:59:41 -05003611
3612 buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3613 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3614 msi_free(buffer);
3615
3616 langid = msi_get_property_int(package, szProductLanguage, 0);
3617 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3618
James Hawkinsebeb5372008-06-23 22:59:41 -05003619 /* FIXME */
3620 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3621
3622 buffer = msi_dup_property(package, szARPProductIcon);
3623 if (buffer)
3624 {
3625 LPWSTR path = build_icon_path(package,buffer);
3626 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3627 msi_free(path);
3628 msi_free(buffer);
3629 }
3630
3631 buffer = msi_dup_property(package, szProductVersion);
3632 if (buffer)
3633 {
3634 DWORD verdword = msi_version_str_to_dword(buffer);
3635 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3636 msi_free(buffer);
3637 }
3638
James Hawkinsef640a62008-06-23 23:01:44 -05003639 msi_reg_set_val_dword(hkey, szAssignment, 0);
3640 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3641 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3642 msi_reg_set_val_str(hkey, szClients, szColon);
3643
James Hawkinsebeb5372008-06-23 22:59:41 -05003644 hdb = alloc_msihandle(&package->db->hdr);
3645 if (!hdb)
3646 return ERROR_NOT_ENOUGH_MEMORY;
3647
3648 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3649 MsiCloseHandle(hdb);
3650 if (r != ERROR_SUCCESS)
3651 goto done;
3652
3653 size = MAX_PATH;
3654 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3655 NULL, guids, &size);
3656 if (r != ERROR_SUCCESS)
3657 goto done;
3658
3659 ptr = strchrW(guids, ';');
3660 if (ptr) *ptr = 0;
James Hawkinsdb2e8d22008-06-23 23:00:21 -05003661 squash_guid(guids, packcode);
3662 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
James Hawkinsebeb5372008-06-23 22:59:41 -05003663
3664done:
3665 MsiCloseHandle(suminfo);
3666 return ERROR_SUCCESS;
3667}
3668
James Hawkinscdb33f82008-06-23 23:02:54 -05003669static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3670{
3671 UINT r;
3672 HKEY hkey;
3673 LPWSTR upgrade;
3674 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3675
3676 static const WCHAR szUpgradeCode[] =
3677 {'U','p','g','r','a','d','e','C','o','d','e',0};
3678
3679 upgrade = msi_dup_property(package, szUpgradeCode);
3680 if (!upgrade)
3681 return ERROR_SUCCESS;
3682
James Hawkins58e15432008-06-23 23:04:46 -05003683 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3684 {
3685 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3686 if (r != ERROR_SUCCESS)
3687 goto done;
3688 }
3689 else
3690 {
3691 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3692 if (r != ERROR_SUCCESS)
3693 goto done;
3694 }
James Hawkinscdb33f82008-06-23 23:02:54 -05003695
3696 squash_guid(package->ProductCode, squashed_pc);
3697 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3698
3699 RegCloseKey(hkey);
3700
3701done:
3702 msi_free(upgrade);
3703 return r;
3704}
3705
James Hawkinsa2df31a2007-07-02 20:21:26 -07003706static BOOL msi_check_publish(MSIPACKAGE *package)
3707{
3708 MSIFEATURE *feature;
3709
3710 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3711 {
3712 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3713 return TRUE;
3714 }
3715
3716 return FALSE;
3717}
3718
James Hawkinscdb33f82008-06-23 23:02:54 -05003719static BOOL msi_check_unpublish(MSIPACKAGE *package)
3720{
3721 MSIFEATURE *feature;
3722
3723 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3724 {
3725 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3726 return FALSE;
3727 }
3728
3729 return TRUE;
3730}
3731
James Hawkins01eb9302008-12-14 21:07:23 -06003732static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3733{
3734 WCHAR patch_squashed[GUID_SIZE];
3735 HKEY patches;
3736 LONG res;
3737 UINT r = ERROR_FUNCTION_FAILED;
3738
James Hawkins01eb9302008-12-14 21:07:23 -06003739 res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3740 &patches, NULL);
3741 if (res != ERROR_SUCCESS)
3742 return ERROR_FUNCTION_FAILED;
3743
3744 squash_guid(package->patch->patchcode, patch_squashed);
3745
3746 res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3747 (const BYTE *)patch_squashed,
3748 (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3749 if (res != ERROR_SUCCESS)
3750 goto done;
3751
3752 res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3753 (const BYTE *)package->patch->transforms,
3754 (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3755 if (res == ERROR_SUCCESS)
3756 r = ERROR_SUCCESS;
3757
3758done:
3759 RegCloseKey(patches);
3760 return r;
3761}
3762
Aric Stewart2cf222f2004-07-06 19:00:23 +00003763/*
3764 * 99% of the work done here is only done for
3765 * advertised installs. However this is where the
3766 * Icon table is processed and written out
Francois Gouget817c5202004-07-16 19:15:40 +00003767 * so that is what I am going to do here.
Aric Stewart2cf222f2004-07-06 19:00:23 +00003768 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003769static UINT ACTION_PublishProduct(MSIPACKAGE *package)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003770{
3771 UINT rc;
Hans Leidekkerc547fb32010-03-05 12:27:49 +01003772 HKEY hukey = NULL, hudkey = NULL;
3773 MSIRECORD *uirow;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003774
James Hawkinsa2df31a2007-07-02 20:21:26 -07003775 /* FIXME: also need to publish if the product is in advertise mode */
3776 if (!msi_check_publish(package))
3777 return ERROR_SUCCESS;
3778
James Hawkinsc965d832009-03-22 14:30:16 -07003779 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
James Hawkins70be1e72008-11-03 22:16:43 -06003780 &hukey, TRUE);
3781 if (rc != ERROR_SUCCESS)
3782 goto end;
3783
James Hawkins4a9f6992008-12-14 21:07:06 -06003784 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3785 NULL, &hudkey, TRUE);
3786 if (rc != ERROR_SUCCESS)
3787 goto end;
Aric Stewart6269f002005-01-17 13:40:39 +00003788
James Hawkinscdb33f82008-06-23 23:02:54 -05003789 rc = msi_publish_upgrade_code(package);
3790 if (rc != ERROR_SUCCESS)
3791 goto end;
James Hawkinsebeb5372008-06-23 22:59:41 -05003792
James Hawkins01eb9302008-12-14 21:07:23 -06003793 if (package->patch)
3794 {
3795 rc = msi_publish_patch(package, hukey, hudkey);
3796 if (rc != ERROR_SUCCESS)
3797 goto end;
3798 }
3799
James Hawkinsebeb5372008-06-23 22:59:41 -05003800 rc = msi_publish_product_properties(package, hukey);
3801 if (rc != ERROR_SUCCESS)
Dan Kegel337e1e22006-08-28 09:44:35 -07003802 goto end;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003803
James Hawkins2d4e4b62008-06-23 23:05:25 -05003804 rc = msi_publish_sourcelist(package, hukey);
James Hawkins68e60712008-06-23 22:57:36 -05003805 if (rc != ERROR_SUCCESS)
3806 goto end;
James Hawkins5e46fc92007-07-02 20:20:20 -07003807
James Hawkins68e60712008-06-23 22:57:36 -05003808 rc = msi_publish_icons(package);
James Hawkinsfac97bb2008-06-23 22:56:56 -05003809
Aric Stewart6269f002005-01-17 13:40:39 +00003810end:
Hans Leidekkerc547fb32010-03-05 12:27:49 +01003811 uirow = MSI_CreateRecord( 1 );
3812 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3813 ui_actiondata( package, szPublishProduct, uirow );
3814 msiobj_release( &uirow->hdr );
3815
Aric Stewart6269f002005-01-17 13:40:39 +00003816 RegCloseKey(hukey);
James Hawkinsc18b7752007-06-26 19:22:46 -07003817 RegCloseKey(hudkey);
Aric Stewart6269f002005-01-17 13:40:39 +00003818
Aric Stewart2cf222f2004-07-06 19:00:23 +00003819 return rc;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003820}
3821
Hans Leidekkerb891d082010-03-02 14:58:55 +01003822static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3823{
3824 WCHAR *filename, *ptr, *folder, *ret;
3825 const WCHAR *dirprop;
3826
3827 filename = msi_dup_record_field( row, 2 );
3828 if (filename && (ptr = strchrW( filename, '|' )))
3829 ptr++;
3830 else
3831 ptr = filename;
3832
3833 dirprop = MSI_RecordGetString( row, 3 );
3834 if (dirprop)
3835 {
3836 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3837 if (!folder)
3838 folder = msi_dup_property( package, dirprop );
3839 }
3840 else
3841 folder = msi_dup_property( package, szWindowsFolder );
3842
3843 if (!folder)
3844 {
3845 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3846 msi_free( filename );
3847 return NULL;
3848 }
3849
3850 ret = build_directory_name( 2, folder, ptr );
3851
3852 msi_free( filename );
3853 msi_free( folder );
3854 return ret;
3855}
3856
Aric Stewartaded32f2005-06-23 09:46:31 +00003857static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3858{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003859 MSIPACKAGE *package = param;
Hans Leidekkerb891d082010-03-02 14:58:55 +01003860 LPCWSTR component, section, key, value, identifier;
3861 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
Aric Stewartaded32f2005-06-23 09:46:31 +00003862 MSIRECORD * uirow;
Mike McCormack38d67a42005-08-22 09:15:23 +00003863 INT action;
3864 MSICOMPONENT *comp;
Aric Stewartaded32f2005-06-23 09:46:31 +00003865
3866 component = MSI_RecordGetString(row, 8);
Mike McCormack38d67a42005-08-22 09:15:23 +00003867 comp = get_loaded_component(package,component);
Hans Leidekker598c5422010-02-16 11:44:47 +01003868 if (!comp)
3869 return ERROR_SUCCESS;
Aric Stewartaded32f2005-06-23 09:46:31 +00003870
Hans Leidekker598c5422010-02-16 11:44:47 +01003871 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewartaded32f2005-06-23 09:46:31 +00003872 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003873 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003874 comp->Action = comp->Installed;
Aric Stewartaded32f2005-06-23 09:46:31 +00003875 return ERROR_SUCCESS;
3876 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003877 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewartaded32f2005-06-23 09:46:31 +00003878
3879 identifier = MSI_RecordGetString(row,1);
Aric Stewartaded32f2005-06-23 09:46:31 +00003880 section = MSI_RecordGetString(row,4);
3881 key = MSI_RecordGetString(row,5);
3882 value = MSI_RecordGetString(row,6);
3883 action = MSI_RecordGetInteger(row,7);
3884
3885 deformat_string(package,section,&deformated_section);
3886 deformat_string(package,key,&deformated_key);
3887 deformat_string(package,value,&deformated_value);
3888
Hans Leidekkerb891d082010-03-02 14:58:55 +01003889 fullname = get_ini_file_name(package, row);
Aric Stewartaded32f2005-06-23 09:46:31 +00003890
3891 if (action == 0)
3892 {
3893 TRACE("Adding value %s to section %s in %s\n",
3894 debugstr_w(deformated_key), debugstr_w(deformated_section),
3895 debugstr_w(fullname));
3896 WritePrivateProfileStringW(deformated_section, deformated_key,
3897 deformated_value, fullname);
3898 }
3899 else if (action == 1)
3900 {
3901 WCHAR returned[10];
3902 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3903 returned, 10, fullname);
3904 if (returned[0] == 0)
3905 {
3906 TRACE("Adding value %s to section %s in %s\n",
3907 debugstr_w(deformated_key), debugstr_w(deformated_section),
3908 debugstr_w(fullname));
3909
3910 WritePrivateProfileStringW(deformated_section, deformated_key,
3911 deformated_value, fullname);
3912 }
3913 }
3914 else if (action == 3)
3915 FIXME("Append to existing section not yet implemented\n");
3916
3917 uirow = MSI_CreateRecord(4);
3918 MSI_RecordSetStringW(uirow,1,identifier);
3919 MSI_RecordSetStringW(uirow,2,deformated_section);
3920 MSI_RecordSetStringW(uirow,3,deformated_key);
3921 MSI_RecordSetStringW(uirow,4,deformated_value);
3922 ui_actiondata(package,szWriteIniValues,uirow);
3923 msiobj_release( &uirow->hdr );
James Hawkinsbf9538f2008-10-27 00:56:04 -05003924
Mike McCormackee034ba2005-09-20 11:59:14 +00003925 msi_free(fullname);
Mike McCormackee034ba2005-09-20 11:59:14 +00003926 msi_free(deformated_key);
3927 msi_free(deformated_value);
3928 msi_free(deformated_section);
Aric Stewartaded32f2005-06-23 09:46:31 +00003929 return ERROR_SUCCESS;
3930}
3931
Aric Stewart516a9c72005-01-14 15:59:26 +00003932static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3933{
3934 UINT rc;
3935 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003936 static const WCHAR ExecSeqQuery[] =
3937 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003938 '`','I','n','i','F','i','l','e','`',0};
Aric Stewart516a9c72005-01-14 15:59:26 +00003939
3940 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3941 if (rc != ERROR_SUCCESS)
3942 {
3943 TRACE("no IniFile table\n");
3944 return ERROR_SUCCESS;
3945 }
3946
Aric Stewartaded32f2005-06-23 09:46:31 +00003947 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
Aric Stewart516a9c72005-01-14 15:59:26 +00003948 msiobj_release(&view->hdr);
3949 return rc;
3950}
3951
Hans Leidekkerb891d082010-03-02 14:58:55 +01003952static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
3953{
3954 MSIPACKAGE *package = param;
3955 LPCWSTR component, section, key, value, identifier;
3956 LPWSTR deformated_section, deformated_key, deformated_value, filename;
3957 MSICOMPONENT *comp;
3958 MSIRECORD *uirow;
3959 INT action;
3960
3961 component = MSI_RecordGetString( row, 8 );
3962 comp = get_loaded_component( package, component );
3963 if (!comp)
3964 return ERROR_SUCCESS;
3965
3966 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3967 {
3968 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3969 comp->Action = comp->Installed;
3970 return ERROR_SUCCESS;
3971 }
3972 comp->Action = INSTALLSTATE_ABSENT;
3973
3974 identifier = MSI_RecordGetString( row, 1 );
3975 section = MSI_RecordGetString( row, 4 );
3976 key = MSI_RecordGetString( row, 5 );
3977 value = MSI_RecordGetString( row, 6 );
3978 action = MSI_RecordGetInteger( row, 7 );
3979
3980 deformat_string( package, section, &deformated_section );
3981 deformat_string( package, key, &deformated_key );
3982 deformat_string( package, value, &deformated_value );
3983
3984 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
3985 {
3986 filename = get_ini_file_name( package, row );
3987
3988 TRACE("Removing key %s from section %s in %s\n",
3989 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
3990
3991 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
3992 {
3993 WARN("Unable to remove key %u\n", GetLastError());
3994 }
3995 msi_free( filename );
3996 }
3997 else
3998 FIXME("Unsupported action %d\n", action);
3999
4000
4001 uirow = MSI_CreateRecord( 4 );
4002 MSI_RecordSetStringW( uirow, 1, identifier );
4003 MSI_RecordSetStringW( uirow, 2, deformated_section );
4004 MSI_RecordSetStringW( uirow, 3, deformated_key );
4005 MSI_RecordSetStringW( uirow, 4, deformated_value );
4006 ui_actiondata( package, szRemoveIniValues, uirow );
4007 msiobj_release( &uirow->hdr );
4008
4009 msi_free( deformated_key );
4010 msi_free( deformated_value );
4011 msi_free( deformated_section );
4012 return ERROR_SUCCESS;
4013}
4014
4015static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4016{
4017 MSIPACKAGE *package = param;
4018 LPCWSTR component, section, key, value, identifier;
4019 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4020 MSICOMPONENT *comp;
4021 MSIRECORD *uirow;
4022 INT action;
4023
4024 component = MSI_RecordGetString( row, 8 );
4025 comp = get_loaded_component( package, component );
4026 if (!comp)
4027 return ERROR_SUCCESS;
4028
4029 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4030 {
4031 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4032 comp->Action = comp->Installed;
4033 return ERROR_SUCCESS;
4034 }
4035 comp->Action = INSTALLSTATE_LOCAL;
4036
4037 identifier = MSI_RecordGetString( row, 1 );
4038 section = MSI_RecordGetString( row, 4 );
4039 key = MSI_RecordGetString( row, 5 );
4040 value = MSI_RecordGetString( row, 6 );
4041 action = MSI_RecordGetInteger( row, 7 );
4042
4043 deformat_string( package, section, &deformated_section );
4044 deformat_string( package, key, &deformated_key );
4045 deformat_string( package, value, &deformated_value );
4046
4047 if (action == msidbIniFileActionRemoveLine)
4048 {
4049 filename = get_ini_file_name( package, row );
4050
4051 TRACE("Removing key %s from section %s in %s\n",
4052 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4053
4054 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4055 {
4056 WARN("Unable to remove key %u\n", GetLastError());
4057 }
4058 msi_free( filename );
4059 }
4060 else
4061 FIXME("Unsupported action %d\n", action);
4062
4063 uirow = MSI_CreateRecord( 4 );
4064 MSI_RecordSetStringW( uirow, 1, identifier );
4065 MSI_RecordSetStringW( uirow, 2, deformated_section );
4066 MSI_RecordSetStringW( uirow, 3, deformated_key );
4067 MSI_RecordSetStringW( uirow, 4, deformated_value );
4068 ui_actiondata( package, szRemoveIniValues, uirow );
4069 msiobj_release( &uirow->hdr );
4070
4071 msi_free( deformated_key );
4072 msi_free( deformated_value );
4073 msi_free( deformated_section );
4074 return ERROR_SUCCESS;
4075}
4076
4077static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4078{
4079 UINT rc;
4080 MSIQUERY *view;
4081 static const WCHAR query[] =
4082 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4083 '`','I','n','i','F','i','l','e','`',0};
4084 static const WCHAR remove_query[] =
4085 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4086 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4087
4088 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4089 if (rc == ERROR_SUCCESS)
4090 {
4091 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4092 msiobj_release( &view->hdr );
4093 if (rc != ERROR_SUCCESS)
4094 return rc;
4095 }
4096
4097 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4098 if (rc == ERROR_SUCCESS)
4099 {
4100 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4101 msiobj_release( &view->hdr );
4102 if (rc != ERROR_SUCCESS)
4103 return rc;
4104 }
4105
4106 return ERROR_SUCCESS;
4107}
4108
Aric Stewart854bfc42005-06-24 11:33:02 +00004109static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
Aric Stewart6269f002005-01-17 13:40:39 +00004110{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01004111 MSIPACKAGE *package = param;
Aric Stewart854bfc42005-06-24 11:33:02 +00004112 LPCWSTR filename;
4113 LPWSTR FullName;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004114 MSIFILE *file;
Aric Stewart854bfc42005-06-24 11:33:02 +00004115 DWORD len;
Aric Stewart8e233e92005-03-01 11:45:19 +00004116 static const WCHAR ExeStr[] =
Aric Stewartc5a14432005-05-18 17:46:12 +00004117 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4118 static const WCHAR close[] = {'\"',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004119 STARTUPINFOW si;
4120 PROCESS_INFORMATION info;
4121 BOOL brc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004122 MSIRECORD *uirow;
4123 LPWSTR uipath, p;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004124
4125 memset(&si,0,sizeof(STARTUPINFOW));
4126
Aric Stewart854bfc42005-06-24 11:33:02 +00004127 filename = MSI_RecordGetString(row,1);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004128 file = get_loaded_file( package, filename );
Aric Stewart854bfc42005-06-24 11:33:02 +00004129
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004130 if (!file)
Aric Stewart854bfc42005-06-24 11:33:02 +00004131 {
4132 ERR("Unable to find file id %s\n",debugstr_w(filename));
4133 return ERROR_SUCCESS;
4134 }
4135
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004136 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
Aric Stewart854bfc42005-06-24 11:33:02 +00004137
Mike McCormackee034ba2005-09-20 11:59:14 +00004138 FullName = msi_alloc(len*sizeof(WCHAR));
Aric Stewart854bfc42005-06-24 11:33:02 +00004139 strcpyW(FullName,ExeStr);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004140 strcatW( FullName, file->TargetPath );
Aric Stewart854bfc42005-06-24 11:33:02 +00004141 strcatW(FullName,close);
4142
4143 TRACE("Registering %s\n",debugstr_w(FullName));
4144 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4145 &si, &info);
4146
4147 if (brc)
Rob Shearmancda469c2008-08-17 18:29:11 +01004148 {
4149 CloseHandle(info.hThread);
Aric Stewart854bfc42005-06-24 11:33:02 +00004150 msi_dialog_check_messages(info.hProcess);
Rob Shearmancda469c2008-08-17 18:29:11 +01004151 CloseHandle(info.hProcess);
4152 }
Aric Stewart854bfc42005-06-24 11:33:02 +00004153
Robert Shearmand2e48e02006-01-23 17:29:50 +01004154 uirow = MSI_CreateRecord( 2 );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004155 MSI_RecordSetStringW( uirow, 1, filename );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004156 uipath = strdupW( file->TargetPath );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004157 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4158 MSI_RecordSetStringW( uirow, 2, uipath );
4159 ui_actiondata( package, szSelfRegModules, uirow );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004160 msiobj_release( &uirow->hdr );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004161
Hans Leidekkera4be9412010-03-23 11:45:33 +01004162 msi_free( FullName );
4163 msi_free( uipath );
Aric Stewart854bfc42005-06-24 11:33:02 +00004164 return ERROR_SUCCESS;
4165}
4166
4167static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4168{
4169 UINT rc;
4170 MSIQUERY * view;
4171 static const WCHAR ExecSeqQuery[] =
4172 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4173 '`','S','e','l','f','R','e','g','`',0};
4174
Aric Stewart6269f002005-01-17 13:40:39 +00004175 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4176 if (rc != ERROR_SUCCESS)
4177 {
4178 TRACE("no SelfReg table\n");
4179 return ERROR_SUCCESS;
4180 }
4181
Aric Stewart854bfc42005-06-24 11:33:02 +00004182 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
Aric Stewart6269f002005-01-17 13:40:39 +00004183 msiobj_release(&view->hdr);
Aric Stewart854bfc42005-06-24 11:33:02 +00004184
4185 return ERROR_SUCCESS;
Aric Stewart6269f002005-01-17 13:40:39 +00004186}
4187
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004188static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4189{
4190 static const WCHAR regsvr32[] =
4191 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4192 static const WCHAR close[] = {'\"',0};
4193 MSIPACKAGE *package = param;
4194 LPCWSTR filename;
4195 LPWSTR cmdline;
4196 MSIFILE *file;
4197 DWORD len;
4198 STARTUPINFOW si;
4199 PROCESS_INFORMATION pi;
4200 BOOL ret;
4201 MSIRECORD *uirow;
4202 LPWSTR uipath, p;
4203
4204 memset( &si, 0, sizeof(STARTUPINFOW) );
4205
4206 filename = MSI_RecordGetString( row, 1 );
4207 file = get_loaded_file( package, filename );
4208
4209 if (!file)
4210 {
4211 ERR("Unable to find file id %s\n", debugstr_w(filename));
4212 return ERROR_SUCCESS;
4213 }
4214
4215 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4216
4217 cmdline = msi_alloc( len * sizeof(WCHAR) );
4218 strcpyW( cmdline, regsvr32 );
4219 strcatW( cmdline, file->TargetPath );
4220 strcatW( cmdline, close );
4221
4222 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4223
4224 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4225 if (ret)
4226 {
4227 CloseHandle( pi.hThread );
4228 msi_dialog_check_messages( pi.hProcess );
4229 CloseHandle( pi.hProcess );
4230 }
4231
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004232 uirow = MSI_CreateRecord( 2 );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004233 MSI_RecordSetStringW( uirow, 1, filename );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004234 uipath = strdupW( file->TargetPath );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004235 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004236 MSI_RecordSetStringW( uirow, 2, uipath );
4237 ui_actiondata( package, szSelfUnregModules, uirow );
4238 msiobj_release( &uirow->hdr );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004239
Hans Leidekkera4be9412010-03-23 11:45:33 +01004240 msi_free( cmdline );
4241 msi_free( uipath );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004242 return ERROR_SUCCESS;
4243}
4244
4245static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4246{
4247 UINT rc;
4248 MSIQUERY *view;
4249 static const WCHAR query[] =
4250 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4251 '`','S','e','l','f','R','e','g','`',0};
4252
4253 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4254 if (rc != ERROR_SUCCESS)
4255 {
4256 TRACE("no SelfReg table\n");
4257 return ERROR_SUCCESS;
4258 }
4259
4260 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4261 msiobj_release( &view->hdr );
4262
4263 return ERROR_SUCCESS;
4264}
4265
Aric Stewart6269f002005-01-17 13:40:39 +00004266static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4267{
Mike McCormack1da28582005-08-22 14:09:17 +00004268 MSIFEATURE *feature;
Aric Stewart6269f002005-01-17 13:40:39 +00004269 UINT rc;
Hans Leidekker353035f2010-03-04 09:17:50 +01004270 HKEY hkey = NULL, userdata = NULL;
James Hawkins6ac08162007-08-09 11:38:48 -07004271
4272 if (!msi_check_publish(package))
4273 return ERROR_SUCCESS;
4274
James Hawkins0c01c582008-11-03 22:16:50 -06004275 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4276 &hkey, TRUE);
4277 if (rc != ERROR_SUCCESS)
4278 goto end;
4279
James Hawkinse3074342008-11-03 22:16:54 -06004280 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4281 &userdata, TRUE);
4282 if (rc != ERROR_SUCCESS)
4283 goto end;
James Hawkins9f11a5a2007-11-01 03:13:28 -05004284
Aric Stewart6269f002005-01-17 13:40:39 +00004285 /* here the guids are base 85 encoded */
Mike McCormack1da28582005-08-22 14:09:17 +00004286 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00004287 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004288 ComponentList *cl;
Aric Stewart6269f002005-01-17 13:40:39 +00004289 LPWSTR data = NULL;
4290 GUID clsid;
Aric Stewart6269f002005-01-17 13:40:39 +00004291 INT size;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004292 BOOL absent = FALSE;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004293 MSIRECORD *uirow;
Aric Stewart6269f002005-01-17 13:40:39 +00004294
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01004295 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4296 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4297 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004298
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004299 size = 1;
Mike McCormack1da28582005-08-22 14:09:17 +00004300 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004301 {
4302 size += 21;
4303 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00004304 if (feature->Feature_Parent)
Mike McCormack1da28582005-08-22 14:09:17 +00004305 size += strlenW( feature->Feature_Parent )+2;
Aric Stewart6269f002005-01-17 13:40:39 +00004306
Mike McCormackee034ba2005-09-20 11:59:14 +00004307 data = msi_alloc(size * sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00004308
4309 data[0] = 0;
Mike McCormack1da28582005-08-22 14:09:17 +00004310 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00004311 {
Mike McCormack38d67a42005-08-22 09:15:23 +00004312 MSICOMPONENT* component = cl->component;
Aric Stewart6269f002005-01-17 13:40:39 +00004313 WCHAR buf[21];
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004314
Mike McCormack3a940112006-04-19 02:29:03 +09004315 buf[0] = 0;
Mike McCormackefcc1ec2005-09-12 12:07:15 +00004316 if (component->ComponentId)
Aric Stewartc5a14432005-05-18 17:46:12 +00004317 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004318 TRACE("From %s\n",debugstr_w(component->ComponentId));
4319 CLSIDFromString(component->ComponentId, &clsid);
Aric Stewartc5a14432005-05-18 17:46:12 +00004320 encode_base85_guid(&clsid,buf);
4321 TRACE("to %s\n",debugstr_w(buf));
4322 strcatW(data,buf);
4323 }
Aric Stewart6269f002005-01-17 13:40:39 +00004324 }
James Hawkins9f11a5a2007-11-01 03:13:28 -05004325
Mike McCormack79ca56c2005-09-13 10:37:37 +00004326 if (feature->Feature_Parent)
Aric Stewart6269f002005-01-17 13:40:39 +00004327 {
4328 static const WCHAR sep[] = {'\2',0};
4329 strcatW(data,sep);
Mike McCormack1da28582005-08-22 14:09:17 +00004330 strcatW(data,feature->Feature_Parent);
Aric Stewart6269f002005-01-17 13:40:39 +00004331 }
4332
James Hawkins9f11a5a2007-11-01 03:13:28 -05004333 msi_reg_set_val_str( userdata, feature->Feature, data );
Mike McCormackee034ba2005-09-20 11:59:14 +00004334 msi_free(data);
Aric Stewart6269f002005-01-17 13:40:39 +00004335
Mike McCormack79ca56c2005-09-13 10:37:37 +00004336 size = 0;
4337 if (feature->Feature_Parent)
4338 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004339 if (!absent)
4340 {
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02004341 size += sizeof(WCHAR);
James Hawkins2a180e02008-06-19 00:32:59 -05004342 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
Hans Leidekker843382f2009-10-15 12:46:27 +02004343 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004344 }
4345 else
4346 {
Mike McCormack79ca56c2005-09-13 10:37:37 +00004347 size += 2*sizeof(WCHAR);
Mike McCormackee034ba2005-09-20 11:59:14 +00004348 data = msi_alloc(size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004349 data[0] = 0x6;
Mike McCormack79ca56c2005-09-13 10:37:37 +00004350 data[1] = 0;
4351 if (feature->Feature_Parent)
4352 strcpyW( &data[1], feature->Feature_Parent );
James Hawkins2a180e02008-06-19 00:32:59 -05004353 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
Mike McCormack16466af2005-07-06 10:33:30 +00004354 (LPBYTE)data,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00004355 msi_free(data);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004356 }
Robert Shearmand2e48e02006-01-23 17:29:50 +01004357
4358 /* the UI chunk */
4359 uirow = MSI_CreateRecord( 1 );
4360 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4361 ui_actiondata( package, szPublishFeatures, uirow);
4362 msiobj_release( &uirow->hdr );
4363 /* FIXME: call ui_progress? */
Aric Stewart6269f002005-01-17 13:40:39 +00004364 }
4365
Aric Stewart6269f002005-01-17 13:40:39 +00004366end:
James Hawkins2a180e02008-06-19 00:32:59 -05004367 RegCloseKey(hkey);
4368 RegCloseKey(userdata);
Aric Stewart6269f002005-01-17 13:40:39 +00004369 return rc;
4370}
4371
James Hawkins6ac08162007-08-09 11:38:48 -07004372static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4373{
4374 UINT r;
4375 HKEY hkey;
Hans Leidekker18a85ca2010-03-23 11:47:19 +01004376 MSIRECORD *uirow;
James Hawkins6ac08162007-08-09 11:38:48 -07004377
4378 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4379
James Hawkins0c01c582008-11-03 22:16:50 -06004380 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4381 &hkey, FALSE);
James Hawkins6ac08162007-08-09 11:38:48 -07004382 if (r == ERROR_SUCCESS)
4383 {
4384 RegDeleteValueW(hkey, feature->Feature);
4385 RegCloseKey(hkey);
4386 }
4387
James Hawkinse3074342008-11-03 22:16:54 -06004388 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4389 &hkey, FALSE);
James Hawkins6ac08162007-08-09 11:38:48 -07004390 if (r == ERROR_SUCCESS)
4391 {
4392 RegDeleteValueW(hkey, feature->Feature);
4393 RegCloseKey(hkey);
4394 }
4395
Hans Leidekker18a85ca2010-03-23 11:47:19 +01004396 uirow = MSI_CreateRecord( 1 );
4397 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4398 ui_actiondata( package, szUnpublishFeatures, uirow );
4399 msiobj_release( &uirow->hdr );
4400
James Hawkins6ac08162007-08-09 11:38:48 -07004401 return ERROR_SUCCESS;
4402}
4403
4404static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4405{
4406 MSIFEATURE *feature;
4407
James Hawkinsccdf5782007-11-01 03:14:18 -05004408 if (!msi_check_unpublish(package))
James Hawkins6ac08162007-08-09 11:38:48 -07004409 return ERROR_SUCCESS;
4410
4411 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4412 {
4413 msi_unpublish_feature(package, feature);
4414 }
4415
4416 return ERROR_SUCCESS;
4417}
4418
James Hawkins45de8962008-06-19 00:36:10 -05004419static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
Mike McCormackba293ee2005-10-27 12:08:16 +00004420{
4421 LPWSTR prop, val, key;
James Hawkins45de8962008-06-19 00:36:10 -05004422 SYSTEMTIME systime;
4423 DWORD size, langid;
4424 WCHAR date[9];
4425 LPWSTR buffer;
4426
4427 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4428 static const WCHAR szWindowsInstaller[] =
4429 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4430 static const WCHAR modpath_fmt[] =
4431 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4432 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4433 static const WCHAR szModifyPath[] =
4434 {'M','o','d','i','f','y','P','a','t','h',0};
4435 static const WCHAR szUninstallString[] =
4436 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4437 static const WCHAR szEstimatedSize[] =
4438 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4439 static const WCHAR szProductLanguage[] =
4440 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4441 static const WCHAR szProductVersion[] =
4442 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4443 static const WCHAR szProductName[] =
4444 {'P','r','o','d','u','c','t','N','a','m','e',0};
4445 static const WCHAR szDisplayName[] =
4446 {'D','i','s','p','l','a','y','N','a','m','e',0};
4447 static const WCHAR szDisplayVersion[] =
4448 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4449 static const WCHAR szManufacturer[] =
4450 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4451
Mike McCormackba293ee2005-10-27 12:08:16 +00004452 static const LPCSTR propval[] = {
4453 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
4454 "ARPCONTACT", "Contact",
4455 "ARPCOMMENTS", "Comments",
4456 "ProductName", "DisplayName",
4457 "ProductVersion", "DisplayVersion",
4458 "ARPHELPLINK", "HelpLink",
4459 "ARPHELPTELEPHONE", "HelpTelephone",
4460 "ARPINSTALLLOCATION", "InstallLocation",
4461 "SourceDir", "InstallSource",
4462 "Manufacturer", "Publisher",
4463 "ARPREADME", "Readme",
4464 "ARPSIZE", "Size",
4465 "ARPURLINFOABOUT", "URLInfoAbout",
4466 "ARPURLUPDATEINFO", "URLUpdateInfo",
4467 NULL,
4468 };
4469 const LPCSTR *p = propval;
4470
James Hawkins45de8962008-06-19 00:36:10 -05004471 while (*p)
Mike McCormackba293ee2005-10-27 12:08:16 +00004472 {
James Hawkins45de8962008-06-19 00:36:10 -05004473 prop = strdupAtoW(*p++);
4474 key = strdupAtoW(*p++);
4475 val = msi_dup_property(package, prop);
4476 msi_reg_set_val_str(hkey, key, val);
Mike McCormackba293ee2005-10-27 12:08:16 +00004477 msi_free(val);
4478 msi_free(key);
4479 msi_free(prop);
4480 }
James Hawkins45de8962008-06-19 00:36:10 -05004481
4482 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4483
4484 size = deformat_string(package, modpath_fmt, &buffer);
4485 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4486 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4487 msi_free(buffer);
4488
4489 /* FIXME: Write real Estimated Size when we have it */
4490 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4491
4492 buffer = msi_dup_property(package, szProductName);
4493 msi_reg_set_val_str(hkey, szDisplayName, buffer);
4494 msi_free(buffer);
4495
4496 buffer = msi_dup_property(package, cszSourceDir);
4497 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4498 msi_free(buffer);
4499
4500 buffer = msi_dup_property(package, szManufacturer);
4501 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
4502 msi_free(buffer);
4503
4504 GetLocalTime(&systime);
4505 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4506 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4507
4508 langid = msi_get_property_int(package, szProductLanguage, 0);
4509 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4510
4511 buffer = msi_dup_property(package, szProductVersion);
4512 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4513 if (buffer)
4514 {
4515 DWORD verdword = msi_version_str_to_dword(buffer);
4516
4517 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4518 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4519 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4520 msi_free(buffer);
4521 }
4522
Mike McCormackba293ee2005-10-27 12:08:16 +00004523 return ERROR_SUCCESS;
4524}
4525
Aric Stewart2cae30b2005-01-19 19:07:40 +00004526static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4527{
James Hawkins45de8962008-06-19 00:36:10 -05004528 WCHAR squashed_pc[SQUISH_GUID_SIZE];
Hans Leidekker4341f182010-03-05 12:28:11 +01004529 MSIRECORD *uirow;
Aric Stewart36a01502005-06-08 19:07:52 +00004530 LPWSTR upgrade_code;
James Hawkins45de8962008-06-19 00:36:10 -05004531 HKEY hkey, props;
4532 HKEY upgrade;
4533 UINT rc;
4534
4535 static const WCHAR szUpgradeCode[] = {
4536 'U','p','g','r','a','d','e','C','o','d','e',0};
James Hawkins0e44e092007-07-02 20:21:58 -07004537
4538 /* FIXME: also need to publish if the product is in advertise mode */
4539 if (!msi_check_publish(package))
4540 return ERROR_SUCCESS;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004541
James Hawkins45de8962008-06-19 00:36:10 -05004542 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004543 if (rc != ERROR_SUCCESS)
Mike McCormackba293ee2005-10-27 12:08:16 +00004544 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004545
James Hawkinsb5e3e192008-12-14 21:07:14 -06004546 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4547 NULL, &props, TRUE);
4548 if (rc != ERROR_SUCCESS)
4549 goto done;
James Hawkinsd52f48f2008-03-06 16:12:40 -06004550
Hans Leidekker8dd3d382009-10-20 14:09:53 +02004551 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4552 msi_free( package->db->localfile );
4553 package->db->localfile = NULL;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004554
James Hawkins45de8962008-06-19 00:36:10 -05004555 rc = msi_publish_install_properties(package, hkey);
4556 if (rc != ERROR_SUCCESS)
4557 goto done;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004558
James Hawkins45de8962008-06-19 00:36:10 -05004559 rc = msi_publish_install_properties(package, props);
4560 if (rc != ERROR_SUCCESS)
4561 goto done;
Aric Stewart36a01502005-06-08 19:07:52 +00004562
James Hawkins45de8962008-06-19 00:36:10 -05004563 upgrade_code = msi_dup_property(package, szUpgradeCode);
Aric Stewart36a01502005-06-08 19:07:52 +00004564 if (upgrade_code)
4565 {
James Hawkins45de8962008-06-19 00:36:10 -05004566 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4567 squash_guid(package->ProductCode, squashed_pc);
4568 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4569 RegCloseKey(upgrade);
Mike McCormackee034ba2005-09-20 11:59:14 +00004570 msi_free(upgrade_code);
Aric Stewart36a01502005-06-08 19:07:52 +00004571 }
James Hawkinsbcba82d2008-04-05 06:02:04 -05004572
James Hawkins45de8962008-06-19 00:36:10 -05004573done:
Hans Leidekker4341f182010-03-05 12:28:11 +01004574 uirow = MSI_CreateRecord( 1 );
4575 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4576 ui_actiondata( package, szRegisterProduct, uirow );
4577 msiobj_release( &uirow->hdr );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004578
Hans Leidekker4341f182010-03-05 12:28:11 +01004579 RegCloseKey(hkey);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004580 return ERROR_SUCCESS;
4581}
4582
4583static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4584{
Mike McCormacka977b2c2005-11-03 09:56:29 +00004585 return execute_script(package,INSTALL_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004586}
4587
James Hawkins624bbbe2007-07-02 20:20:54 -07004588static UINT msi_unpublish_product(MSIPACKAGE *package)
4589{
James Hawkinscdb33f82008-06-23 23:02:54 -05004590 LPWSTR upgrade;
James Hawkins624bbbe2007-07-02 20:20:54 -07004591 LPWSTR remove = NULL;
4592 LPWSTR *features = NULL;
4593 BOOL full_uninstall = TRUE;
4594 MSIFEATURE *feature;
4595
James Hawkinscdb33f82008-06-23 23:02:54 -05004596 static const WCHAR szUpgradeCode[] =
4597 {'U','p','g','r','a','d','e','C','o','d','e',0};
James Hawkins624bbbe2007-07-02 20:20:54 -07004598
4599 remove = msi_dup_property(package, szRemove);
4600 if (!remove)
4601 return ERROR_SUCCESS;
4602
4603 features = msi_split_string(remove, ',');
4604 if (!features)
4605 {
4606 msi_free(remove);
4607 ERR("REMOVE feature list is empty!\n");
4608 return ERROR_FUNCTION_FAILED;
4609 }
4610
4611 if (!lstrcmpW(features[0], szAll))
4612 full_uninstall = TRUE;
4613 else
4614 {
4615 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4616 {
4617 if (feature->Action != INSTALLSTATE_ABSENT)
4618 full_uninstall = FALSE;
4619 }
4620 }
4621
4622 if (!full_uninstall)
4623 goto done;
4624
4625 MSIREG_DeleteProductKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004626 MSIREG_DeleteUserDataProductKey(package->ProductCode);
James Hawkinsf6b27672007-11-13 00:47:21 -06004627 MSIREG_DeleteUninstallKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004628
James Hawkins38106ac2008-07-28 18:46:32 -05004629 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4630 {
4631 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4632 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4633 }
4634 else
4635 {
4636 MSIREG_DeleteUserProductKey(package->ProductCode);
4637 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4638 }
4639
James Hawkinscdb33f82008-06-23 23:02:54 -05004640 upgrade = msi_dup_property(package, szUpgradeCode);
4641 if (upgrade)
4642 {
4643 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4644 msi_free(upgrade);
4645 }
4646
James Hawkins624bbbe2007-07-02 20:20:54 -07004647done:
4648 msi_free(remove);
4649 msi_free(features);
4650 return ERROR_SUCCESS;
4651}
4652
Aric Stewart2cae30b2005-01-19 19:07:40 +00004653static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4654{
Aric Stewart9cd707d2005-05-27 19:24:22 +00004655 UINT rc;
4656
James Hawkins624bbbe2007-07-02 20:20:54 -07004657 rc = msi_unpublish_product(package);
4658 if (rc != ERROR_SUCCESS)
4659 return rc;
4660
Francois Gouget1ccf9442006-11-12 19:51:37 +01004661 /* turn off scheduling */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004662 package->script->CurrentlyScripting= FALSE;
4663
Aric Stewart54c67dd2005-01-25 20:17:09 +00004664 /* first do the same as an InstallExecute */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004665 rc = ACTION_InstallExecute(package);
4666 if (rc != ERROR_SUCCESS)
4667 return rc;
Aric Stewart54c67dd2005-01-25 20:17:09 +00004668
4669 /* then handle Commit Actions */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004670 rc = execute_script(package,COMMIT_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004671
Aric Stewart9cd707d2005-05-27 19:24:22 +00004672 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004673}
4674
James Hawkinsc2e91582007-05-29 12:03:05 -07004675UINT ACTION_ForceReboot(MSIPACKAGE *package)
Aric Stewart2cae30b2005-01-19 19:07:40 +00004676{
4677 static const WCHAR RunOnce[] = {
4678 'S','o','f','t','w','a','r','e','\\',
4679 'M','i','c','r','o','s','o','f','t','\\',
4680 'W','i','n','d','o','w','s','\\',
4681 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004682 'R','u','n','O','n','c','e',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004683 static const WCHAR InstallRunOnce[] = {
4684 'S','o','f','t','w','a','r','e','\\',
4685 'M','i','c','r','o','s','o','f','t','\\',
4686 'W','i','n','d','o','w','s','\\',
4687 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4688 'I','n','s','t','a','l','l','e','r','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004689 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004690
4691 static const WCHAR msiexec_fmt[] = {
Juan Lang014ad3b2005-03-01 10:41:52 +00004692 '%','s',
Aric Stewart2cae30b2005-01-19 19:07:40 +00004693 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4694 '\"','%','s','\"',0};
4695 static const WCHAR install_fmt[] = {
4696 '/','I',' ','\"','%','s','\"',' ',
4697 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4698 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
Juan Lang014ad3b2005-03-01 10:41:52 +00004699 WCHAR buffer[256], sysdir[MAX_PATH];
Aric Stewartadaef112005-07-07 20:27:06 +00004700 HKEY hkey;
Mike McCormack4db02cd2005-09-15 14:58:38 +00004701 WCHAR squished_pc[100];
Aric Stewart2cae30b2005-01-19 19:07:40 +00004702
Aric Stewartadaef112005-07-07 20:27:06 +00004703 squash_guid(package->ProductCode,squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004704
Juan Lang014ad3b2005-03-01 10:41:52 +00004705 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
Aric Stewart2cae30b2005-01-19 19:07:40 +00004706 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
Juan Lang014ad3b2005-03-01 10:41:52 +00004707 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4708 squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004709
Mike McCormack4db02cd2005-09-15 14:58:38 +00004710 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004711 RegCloseKey(hkey);
4712
4713 TRACE("Reboot command %s\n",debugstr_w(buffer));
4714
4715 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
Aric Stewartadaef112005-07-07 20:27:06 +00004716 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004717
Mike McCormack4db02cd2005-09-15 14:58:38 +00004718 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004719 RegCloseKey(hkey);
4720
Aric Stewart68b07492005-01-25 11:05:37 +00004721 return ERROR_INSTALL_SUSPEND;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004722}
4723
James Hawkins563a50a2006-10-09 00:05:04 -07004724static UINT ACTION_ResolveSource(MSIPACKAGE* package)
Aric Stewart90c57392005-01-31 16:23:12 +00004725{
Mike McCormackb9211182006-11-20 16:27:36 +09004726 DWORD attrib;
Aric Stewart94d68182005-08-15 20:50:06 +00004727 UINT rc;
Mike McCormackfc564232006-11-20 16:17:03 +09004728
Aric Stewart90c57392005-01-31 16:23:12 +00004729 /*
Mike McCormackfc564232006-11-20 16:17:03 +09004730 * We are currently doing what should be done here in the top level Install
4731 * however for Administrative and uninstalls this step will be needed
Aric Stewart90c57392005-01-31 16:23:12 +00004732 */
Aric Stewart94d68182005-08-15 20:50:06 +00004733 if (!package->PackagePath)
4734 return ERROR_SUCCESS;
4735
James Hawkinsc777d302008-01-05 13:45:13 -07004736 msi_set_sourcedir_props(package, TRUE);
James Hawkinsc5075432006-10-10 13:39:50 -07004737
James Hawkinse28cedf2008-01-05 13:48:32 -07004738 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004739 if (attrib == INVALID_FILE_ATTRIBUTES)
4740 {
4741 LPWSTR prompt;
4742 LPWSTR msg;
4743 DWORD size = 0;
4744
4745 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004746 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004747 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4748 if (rc == ERROR_MORE_DATA)
4749 {
Mike McCormackee034ba2005-09-20 11:59:14 +00004750 prompt = msi_alloc(size * sizeof(WCHAR));
Aric Stewart94d68182005-08-15 20:50:06 +00004751 MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004752 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004753 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4754 }
4755 else
James Hawkinse28cedf2008-01-05 13:48:32 -07004756 prompt = strdupW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004757
4758 msg = generate_error_string(package,1302,1,prompt);
4759 while(attrib == INVALID_FILE_ATTRIBUTES)
4760 {
4761 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4762 if (rc == IDCANCEL)
4763 {
4764 rc = ERROR_INSTALL_USEREXIT;
4765 break;
4766 }
James Hawkinse28cedf2008-01-05 13:48:32 -07004767 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004768 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004769 msi_free(prompt);
Aric Stewart94d68182005-08-15 20:50:06 +00004770 rc = ERROR_SUCCESS;
4771 }
4772 else
4773 return ERROR_SUCCESS;
4774
4775 return rc;
Aric Stewart90c57392005-01-31 16:23:12 +00004776}
4777
Aric Stewartc7e88e02005-02-10 17:09:44 +00004778static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4779{
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004780 HKEY hkey = 0;
4781 LPWSTR buffer, productid = NULL;
4782 UINT i, rc = ERROR_SUCCESS;
4783 MSIRECORD *uirow;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004784
4785 static const WCHAR szPropKeys[][80] =
4786 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004787 {'P','r','o','d','u','c','t','I','D',0},
4788 {'U','S','E','R','N','A','M','E',0},
4789 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4790 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004791 };
4792
4793 static const WCHAR szRegKeys[][80] =
4794 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004795 {'P','r','o','d','u','c','t','I','D',0},
4796 {'R','e','g','O','w','n','e','r',0},
4797 {'R','e','g','C','o','m','p','a','n','y',0},
4798 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004799 };
4800
James Hawkinsd52f48f2008-03-06 16:12:40 -06004801 if (msi_check_unpublish(package))
4802 {
4803 MSIREG_DeleteUserDataProductKey(package->ProductCode);
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004804 goto end;
James Hawkinsd52f48f2008-03-06 16:12:40 -06004805 }
4806
Mike McCormack062ad502005-09-15 15:04:08 +00004807 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004808 if (!productid)
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004809 goto end;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004810
James Hawkinsb5e3e192008-12-14 21:07:14 -06004811 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4812 NULL, &hkey, TRUE);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004813 if (rc != ERROR_SUCCESS)
4814 goto end;
4815
Mike McCormack67189f92005-09-16 18:45:19 +00004816 for( i = 0; szPropKeys[i][0]; i++ )
Aric Stewartc7e88e02005-02-10 17:09:44 +00004817 {
Mike McCormack062ad502005-09-15 15:04:08 +00004818 buffer = msi_dup_property( package, szPropKeys[i] );
Mike McCormack4db02cd2005-09-15 14:58:38 +00004819 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00004820 msi_free( buffer );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004821 }
4822
4823end:
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004824 uirow = MSI_CreateRecord( 1 );
4825 MSI_RecordSetStringW( uirow, 1, productid );
4826 ui_actiondata( package, szRegisterUser, uirow );
4827 msiobj_release( &uirow->hdr );
4828
Mike McCormackee034ba2005-09-20 11:59:14 +00004829 msi_free(productid);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004830 RegCloseKey(hkey);
James Hawkinsd52f48f2008-03-06 16:12:40 -06004831 return rc;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004832}
4833
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004834
4835static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4836{
4837 UINT rc;
Aric Stewart25f1e752005-06-24 12:14:52 +00004838
Aric Stewartc9802932005-06-30 20:45:43 +00004839 package->script->InWhatSequence |= SEQUENCE_EXEC;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004840 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004841 return rc;
4842}
4843
Aric Stewart0af24872005-02-25 14:00:09 +00004844
Aric Stewart072c5e52005-04-20 12:50:05 +00004845static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4846{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01004847 MSIPACKAGE *package = param;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004848 LPCWSTR compgroupid, component, feature, qualifier, text;
4849 LPWSTR advertise = NULL, output = NULL;
Hans Leidekker353035f2010-03-04 09:17:50 +01004850 HKEY hkey = NULL;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004851 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00004852 MSICOMPONENT *comp;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004853 MSIFEATURE *feat;
4854 DWORD sz;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004855 MSIRECORD *uirow;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004856
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004857 feature = MSI_RecordGetString(rec, 5);
4858 feat = get_loaded_feature(package, feature);
4859 if (!feat)
Hans Leidekker598c5422010-02-16 11:44:47 +01004860 return ERROR_SUCCESS;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004861
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004862 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
4863 feat->ActionRequest != INSTALLSTATE_SOURCE &&
4864 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004865 {
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004866 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
4867 feat->Action = feat->Installed;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004868 return ERROR_SUCCESS;
4869 }
Aric Stewart072c5e52005-04-20 12:50:05 +00004870
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01004871 component = MSI_RecordGetString(rec, 3);
4872 comp = get_loaded_component(package, component);
4873 if (!comp)
4874 return ERROR_SUCCESS;
4875
Aric Stewart09b0aba2005-06-09 20:30:59 +00004876 compgroupid = MSI_RecordGetString(rec,1);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004877 qualifier = MSI_RecordGetString(rec,2);
Aric Stewart072c5e52005-04-20 12:50:05 +00004878
4879 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4880 if (rc != ERROR_SUCCESS)
4881 goto end;
4882
Aric Stewart09b0aba2005-06-09 20:30:59 +00004883 text = MSI_RecordGetString(rec,4);
Mike McCormack38d67a42005-08-22 09:15:23 +00004884 advertise = create_component_advertise_string(package, comp, feature);
Aric Stewart072c5e52005-04-20 12:50:05 +00004885
Aric Stewart6f43c182005-05-26 12:24:28 +00004886 sz = strlenW(advertise);
4887
Aric Stewart072c5e52005-04-20 12:50:05 +00004888 if (text)
4889 sz += lstrlenW(text);
Aric Stewart072c5e52005-04-20 12:50:05 +00004890
4891 sz+=3;
4892 sz *= sizeof(WCHAR);
4893
Mike McCormack3a940112006-04-19 02:29:03 +09004894 output = msi_alloc_zero(sz);
Aric Stewart6f43c182005-05-26 12:24:28 +00004895 strcpyW(output,advertise);
Mike McCormack470f23d2005-09-22 10:56:26 +00004896 msi_free(advertise);
Aric Stewart072c5e52005-04-20 12:50:05 +00004897
4898 if (text)
4899 strcatW(output,text);
4900
Mike McCormack4db02cd2005-09-15 14:58:38 +00004901 msi_reg_set_val_multi_str( hkey, qualifier, output );
Aric Stewart072c5e52005-04-20 12:50:05 +00004902
4903end:
4904 RegCloseKey(hkey);
Mike McCormackee034ba2005-09-20 11:59:14 +00004905 msi_free(output);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004906
4907 /* the UI chunk */
4908 uirow = MSI_CreateRecord( 2 );
4909 MSI_RecordSetStringW( uirow, 1, compgroupid );
4910 MSI_RecordSetStringW( uirow, 2, qualifier);
4911 ui_actiondata( package, szPublishComponents, uirow);
4912 msiobj_release( &uirow->hdr );
4913 /* FIXME: call ui_progress? */
4914
Aric Stewart072c5e52005-04-20 12:50:05 +00004915 return rc;
4916}
4917
4918/*
4919 * At present I am ignorning the advertised components part of this and only
4920 * focusing on the qualified component sets
4921 */
4922static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4923{
4924 UINT rc;
4925 MSIQUERY * view;
4926 static const WCHAR ExecSeqQuery[] =
4927 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00004928 '`','P','u','b','l','i','s','h',
4929 'C','o','m','p','o','n','e','n','t','`',0};
Aric Stewart072c5e52005-04-20 12:50:05 +00004930
4931 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4932 if (rc != ERROR_SUCCESS)
4933 return ERROR_SUCCESS;
4934
4935 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4936 msiobj_release(&view->hdr);
4937
4938 return rc;
4939}
Mike McCormack202166c2005-09-23 10:09:18 +00004940
Hans Leidekker0f0e81d2010-02-17 09:55:31 +01004941static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
4942{
4943 static const WCHAR szInstallerComponents[] = {
4944 'S','o','f','t','w','a','r','e','\\',
4945 'M','i','c','r','o','s','o','f','t','\\',
4946 'I','n','s','t','a','l','l','e','r','\\',
4947 'C','o','m','p','o','n','e','n','t','s','\\',0};
4948
4949 MSIPACKAGE *package = param;
4950 LPCWSTR compgroupid, component, feature, qualifier;
4951 MSICOMPONENT *comp;
4952 MSIFEATURE *feat;
4953 MSIRECORD *uirow;
4954 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
4955 LONG res;
4956
4957 feature = MSI_RecordGetString( rec, 5 );
4958 feat = get_loaded_feature( package, feature );
4959 if (!feat)
4960 return ERROR_SUCCESS;
4961
4962 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
4963 {
4964 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
4965 feat->Action = feat->Installed;
4966 return ERROR_SUCCESS;
4967 }
4968
4969 component = MSI_RecordGetString( rec, 3 );
4970 comp = get_loaded_component( package, component );
4971 if (!comp)
4972 return ERROR_SUCCESS;
4973
4974 compgroupid = MSI_RecordGetString( rec, 1 );
4975 qualifier = MSI_RecordGetString( rec, 2 );
4976
4977 squash_guid( compgroupid, squashed );
4978 strcpyW( keypath, szInstallerComponents );
4979 strcatW( keypath, squashed );
4980
4981 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
4982 if (res != ERROR_SUCCESS)
4983 {
4984 WARN("Unable to delete component key %d\n", res);
4985 }
4986
4987 uirow = MSI_CreateRecord( 2 );
4988 MSI_RecordSetStringW( uirow, 1, compgroupid );
4989 MSI_RecordSetStringW( uirow, 2, qualifier );
4990 ui_actiondata( package, szUnpublishComponents, uirow );
4991 msiobj_release( &uirow->hdr );
4992
4993 return ERROR_SUCCESS;
4994}
4995
4996static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
4997{
4998 UINT rc;
4999 MSIQUERY *view;
5000 static const WCHAR query[] =
5001 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5002 '`','P','u','b','l','i','s','h',
5003 'C','o','m','p','o','n','e','n','t','`',0};
5004
5005 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5006 if (rc != ERROR_SUCCESS)
5007 return ERROR_SUCCESS;
5008
5009 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5010 msiobj_release( &view->hdr );
5011
5012 return rc;
5013}
5014
James Hawkins9bc12ad2006-10-19 15:49:54 -07005015static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5016{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005017 MSIPACKAGE *package = param;
James Hawkins9bc12ad2006-10-19 15:49:54 -07005018 MSIRECORD *row;
5019 MSIFILE *file;
5020 SC_HANDLE hscm, service = NULL;
James Hawkinsde4cab22008-03-11 18:08:57 -05005021 LPCWSTR comp, depends, pass;
Marcus Meissnerdb71fb12008-03-13 21:54:48 +01005022 LPWSTR name = NULL, disp = NULL;
James Hawkins9bc12ad2006-10-19 15:49:54 -07005023 LPCWSTR load_order, serv_name, key;
5024 DWORD serv_type, start_type;
5025 DWORD err_control;
5026
5027 static const WCHAR query[] =
5028 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5029 '`','C','o','m','p','o','n','e','n','t','`',' ',
5030 'W','H','E','R','E',' ',
5031 '`','C','o','m','p','o','n','e','n','t','`',' ',
5032 '=','\'','%','s','\'',0};
5033
5034 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5035 if (!hscm)
5036 {
5037 ERR("Failed to open the SC Manager!\n");
5038 goto done;
5039 }
5040
5041 start_type = MSI_RecordGetInteger(rec, 5);
5042 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5043 goto done;
5044
5045 depends = MSI_RecordGetString(rec, 8);
5046 if (depends && *depends)
5047 FIXME("Dependency list unhandled!\n");
5048
James Hawkinsde4cab22008-03-11 18:08:57 -05005049 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5050 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005051 serv_type = MSI_RecordGetInteger(rec, 4);
5052 err_control = MSI_RecordGetInteger(rec, 6);
5053 load_order = MSI_RecordGetString(rec, 7);
5054 serv_name = MSI_RecordGetString(rec, 9);
5055 pass = MSI_RecordGetString(rec, 10);
5056 comp = MSI_RecordGetString(rec, 12);
5057
5058 /* fetch the service path */
5059 row = MSI_QueryGetRecord(package->db, query, comp);
5060 if (!row)
5061 {
5062 ERR("Control query failed!\n");
5063 goto done;
5064 }
5065
5066 key = MSI_RecordGetString(row, 6);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005067
5068 file = get_loaded_file(package, key);
James Hawkinsb6cfc402007-10-23 03:06:59 -05005069 msiobj_release(&row->hdr);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005070 if (!file)
5071 {
5072 ERR("Failed to load the service file\n");
5073 goto done;
5074 }
5075
5076 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5077 start_type, err_control, file->TargetPath,
5078 load_order, NULL, NULL, serv_name, pass);
5079 if (!service)
5080 {
5081 if (GetLastError() != ERROR_SERVICE_EXISTS)
5082 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5083 }
5084
5085done:
5086 CloseServiceHandle(service);
5087 CloseServiceHandle(hscm);
James Hawkinsde4cab22008-03-11 18:08:57 -05005088 msi_free(name);
5089 msi_free(disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005090
5091 return ERROR_SUCCESS;
5092}
5093
5094static UINT ACTION_InstallServices( MSIPACKAGE *package )
5095{
5096 UINT rc;
5097 MSIQUERY * view;
5098 static const WCHAR ExecSeqQuery[] =
5099 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5100 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5101
5102 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5103 if (rc != ERROR_SUCCESS)
5104 return ERROR_SUCCESS;
5105
5106 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5107 msiobj_release(&view->hdr);
5108
5109 return rc;
5110}
5111
James Hawkins58bb3572006-12-01 13:22:59 -08005112/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
James Hawkinscf8e9e32007-11-05 04:37:44 -05005113static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
James Hawkins58bb3572006-12-01 13:22:59 -08005114{
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005115 LPCWSTR *vector, *temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08005116 LPWSTR p, q;
5117 DWORD sep_len;
5118
5119 static const WCHAR separator[] = {'[','~',']',0};
5120
5121 *numargs = 0;
5122 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5123
5124 if (!args)
5125 return NULL;
5126
5127 vector = msi_alloc(sizeof(LPWSTR));
5128 if (!vector)
5129 return NULL;
5130
5131 p = args;
5132 do
5133 {
5134 (*numargs)++;
5135 vector[*numargs - 1] = p;
5136
5137 if ((q = strstrW(p, separator)))
5138 {
5139 *q = '\0';
5140
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005141 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5142 if (!temp_vector)
5143 {
5144 msi_free(vector);
James Hawkins58bb3572006-12-01 13:22:59 -08005145 return NULL;
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005146 }
5147 vector = temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08005148
5149 p = q + sep_len;
5150 }
5151 } while (q);
5152
5153 return vector;
5154}
5155
James Hawkins58bb3572006-12-01 13:22:59 -08005156static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5157{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005158 MSIPACKAGE *package = param;
James Hawkins58bb3572006-12-01 13:22:59 -08005159 MSICOMPONENT *comp;
Hans Leidekkerf7879b42010-02-12 10:33:23 +01005160 SC_HANDLE scm = NULL, service = NULL;
Hans Leidekker87448dc2010-03-02 14:56:01 +01005161 LPCWSTR component, *vector = NULL;
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005162 LPWSTR name, args;
James Hawkins58bb3572006-12-01 13:22:59 -08005163 DWORD event, numargs;
5164 UINT r = ERROR_FUNCTION_FAILED;
5165
Hans Leidekker87448dc2010-03-02 14:56:01 +01005166 component = MSI_RecordGetString(rec, 6);
5167 comp = get_loaded_component(package, component);
5168 if (!comp)
James Hawkins58bb3572006-12-01 13:22:59 -08005169 return ERROR_SUCCESS;
5170
Hans Leidekker87448dc2010-03-02 14:56:01 +01005171 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5172 {
5173 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5174 comp->Action = comp->Installed;
5175 return ERROR_SUCCESS;
5176 }
5177 comp->Action = INSTALLSTATE_LOCAL;
5178
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005179 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5180 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
James Hawkins58bb3572006-12-01 13:22:59 -08005181 event = MSI_RecordGetInteger(rec, 3);
James Hawkins58bb3572006-12-01 13:22:59 -08005182
5183 if (!(event & msidbServiceControlEventStart))
Hans Leidekkerf7879b42010-02-12 10:33:23 +01005184 {
5185 r = ERROR_SUCCESS;
5186 goto done;
5187 }
James Hawkins58bb3572006-12-01 13:22:59 -08005188
5189 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5190 if (!scm)
5191 {
5192 ERR("Failed to open the service control manager\n");
5193 goto done;
5194 }
5195
5196 service = OpenServiceW(scm, name, SERVICE_START);
5197 if (!service)
5198 {
Hans Leidekkeraa196382010-01-28 11:06:05 +01005199 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
James Hawkins58bb3572006-12-01 13:22:59 -08005200 goto done;
5201 }
5202
James Hawkinscf8e9e32007-11-05 04:37:44 -05005203 vector = msi_service_args_to_vector(args, &numargs);
James Hawkins58bb3572006-12-01 13:22:59 -08005204
Hans Leidekker246f9302010-02-01 09:55:08 +01005205 if (!StartServiceW(service, numargs, vector) &&
5206 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
James Hawkins58bb3572006-12-01 13:22:59 -08005207 {
Hans Leidekkeraa196382010-01-28 11:06:05 +01005208 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
James Hawkins58bb3572006-12-01 13:22:59 -08005209 goto done;
5210 }
5211
5212 r = ERROR_SUCCESS;
5213
5214done:
5215 CloseServiceHandle(service);
5216 CloseServiceHandle(scm);
5217
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005218 msi_free(name);
James Hawkins58bb3572006-12-01 13:22:59 -08005219 msi_free(args);
5220 msi_free(vector);
5221 return r;
5222}
5223
5224static UINT ACTION_StartServices( MSIPACKAGE *package )
5225{
5226 UINT rc;
5227 MSIQUERY *view;
5228
5229 static const WCHAR query[] = {
5230 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5231 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5232
5233 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5234 if (rc != ERROR_SUCCESS)
5235 return ERROR_SUCCESS;
5236
5237 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5238 msiobj_release(&view->hdr);
5239
5240 return rc;
5241}
5242
James Hawkinsfb508ff2008-03-24 01:31:07 -05005243static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5244{
5245 DWORD i, needed, count;
5246 ENUM_SERVICE_STATUSW *dependencies;
5247 SERVICE_STATUS ss;
5248 SC_HANDLE depserv;
5249
5250 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5251 0, &needed, &count))
5252 return TRUE;
5253
5254 if (GetLastError() != ERROR_MORE_DATA)
5255 return FALSE;
5256
5257 dependencies = msi_alloc(needed);
5258 if (!dependencies)
5259 return FALSE;
5260
5261 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5262 needed, &needed, &count))
5263 goto error;
5264
5265 for (i = 0; i < count; i++)
5266 {
5267 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5268 SERVICE_STOP | SERVICE_QUERY_STATUS);
5269 if (!depserv)
5270 goto error;
5271
5272 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5273 goto error;
5274 }
5275
5276 return TRUE;
5277
5278error:
5279 msi_free(dependencies);
5280 return FALSE;
5281}
5282
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005283static UINT stop_service( LPCWSTR name )
James Hawkinsfb508ff2008-03-24 01:31:07 -05005284{
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005285 SC_HANDLE scm = NULL, service = NULL;
James Hawkinsfb508ff2008-03-24 01:31:07 -05005286 SERVICE_STATUS status;
5287 SERVICE_STATUS_PROCESS ssp;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005288 DWORD needed;
James Hawkinsfb508ff2008-03-24 01:31:07 -05005289
5290 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5291 if (!scm)
5292 {
5293 WARN("Failed to open the SCM: %d\n", GetLastError());
5294 goto done;
5295 }
5296
5297 service = OpenServiceW(scm, name,
5298 SERVICE_STOP |
5299 SERVICE_QUERY_STATUS |
5300 SERVICE_ENUMERATE_DEPENDENTS);
5301 if (!service)
5302 {
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005303 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
James Hawkinsfb508ff2008-03-24 01:31:07 -05005304 goto done;
5305 }
5306
5307 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5308 sizeof(SERVICE_STATUS_PROCESS), &needed))
5309 {
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005310 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
James Hawkinsfb508ff2008-03-24 01:31:07 -05005311 goto done;
5312 }
5313
5314 if (ssp.dwCurrentState == SERVICE_STOPPED)
5315 goto done;
5316
5317 stop_service_dependents(scm, service);
5318
James Hawkinsddfefc02008-03-24 16:16:58 -05005319 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
James Hawkinsfb508ff2008-03-24 01:31:07 -05005320 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5321
5322done:
5323 CloseServiceHandle(service);
5324 CloseServiceHandle(scm);
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005325
5326 return ERROR_SUCCESS;
5327}
5328
5329static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5330{
5331 MSIPACKAGE *package = param;
5332 MSICOMPONENT *comp;
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005333 LPCWSTR component;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005334 LPWSTR name;
5335 DWORD event;
5336
5337 event = MSI_RecordGetInteger( rec, 3 );
5338 if (!(event & msidbServiceControlEventStop))
5339 return ERROR_SUCCESS;
5340
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005341 component = MSI_RecordGetString( rec, 6 );
5342 comp = get_loaded_component( package, component );
5343 if (!comp)
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005344 return ERROR_SUCCESS;
5345
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005346 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5347 {
5348 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5349 comp->Action = comp->Installed;
5350 return ERROR_SUCCESS;
5351 }
5352 comp->Action = INSTALLSTATE_ABSENT;
5353
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005354 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5355 stop_service( name );
5356 msi_free( name );
James Hawkinsfb508ff2008-03-24 01:31:07 -05005357
5358 return ERROR_SUCCESS;
5359}
5360
5361static UINT ACTION_StopServices( MSIPACKAGE *package )
5362{
5363 UINT rc;
5364 MSIQUERY *view;
5365
5366 static const WCHAR query[] = {
5367 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5368 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5369
5370 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5371 if (rc != ERROR_SUCCESS)
5372 return ERROR_SUCCESS;
5373
5374 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5375 msiobj_release(&view->hdr);
5376
5377 return rc;
5378}
5379
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005380static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5381{
5382 MSIPACKAGE *package = param;
5383 MSICOMPONENT *comp;
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005384 MSIRECORD *uirow;
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005385 LPCWSTR component;
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005386 LPWSTR name = NULL, display_name = NULL;
5387 DWORD event, len;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005388 SC_HANDLE scm = NULL, service = NULL;
5389
5390 event = MSI_RecordGetInteger( rec, 3 );
5391 if (!(event & msidbServiceControlEventDelete))
5392 return ERROR_SUCCESS;
5393
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005394 component = MSI_RecordGetString(rec, 6);
5395 comp = get_loaded_component(package, component);
5396 if (!comp)
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005397 return ERROR_SUCCESS;
5398
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005399 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5400 {
5401 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5402 comp->Action = comp->Installed;
5403 return ERROR_SUCCESS;
5404 }
5405 comp->Action = INSTALLSTATE_ABSENT;
5406
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005407 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5408 stop_service( name );
5409
5410 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5411 if (!scm)
5412 {
5413 WARN("Failed to open the SCM: %d\n", GetLastError());
5414 goto done;
5415 }
5416
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005417 len = 0;
5418 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5419 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5420 {
5421 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5422 GetServiceDisplayNameW( scm, name, display_name, &len );
5423 }
5424
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005425 service = OpenServiceW( scm, name, DELETE );
5426 if (!service)
5427 {
5428 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5429 goto done;
5430 }
5431
5432 if (!DeleteService( service ))
5433 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5434
5435done:
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005436 uirow = MSI_CreateRecord( 2 );
5437 MSI_RecordSetStringW( uirow, 1, display_name );
5438 MSI_RecordSetStringW( uirow, 2, name );
5439 ui_actiondata( package, szDeleteServices, uirow );
5440 msiobj_release( &uirow->hdr );
5441
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005442 CloseServiceHandle( service );
5443 CloseServiceHandle( scm );
5444 msi_free( name );
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005445 msi_free( display_name );
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005446
5447 return ERROR_SUCCESS;
5448}
5449
5450static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5451{
5452 UINT rc;
5453 MSIQUERY *view;
5454
5455 static const WCHAR query[] = {
5456 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5457 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5458
5459 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5460 if (rc != ERROR_SUCCESS)
5461 return ERROR_SUCCESS;
5462
5463 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5464 msiobj_release( &view->hdr );
5465
5466 return rc;
5467}
5468
James Hawkinsd3bec322006-11-27 18:20:33 -08005469static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5470{
5471 MSIFILE *file;
5472
5473 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5474 {
5475 if (!lstrcmpW(file->File, filename))
5476 return file;
5477 }
5478
5479 return NULL;
5480}
5481
5482static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5483{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005484 MSIPACKAGE *package = param;
James Hawkinsd3bec322006-11-27 18:20:33 -08005485 LPWSTR driver, driver_path, ptr;
5486 WCHAR outpath[MAX_PATH];
5487 MSIFILE *driver_file, *setup_file;
Hans Leidekkereff05032010-03-05 12:25:55 +01005488 MSIRECORD *uirow;
James Hawkinsd3bec322006-11-27 18:20:33 -08005489 LPCWSTR desc;
5490 DWORD len, usage;
5491 UINT r = ERROR_SUCCESS;
5492
5493 static const WCHAR driver_fmt[] = {
5494 'D','r','i','v','e','r','=','%','s',0};
5495 static const WCHAR setup_fmt[] = {
5496 'S','e','t','u','p','=','%','s',0};
5497 static const WCHAR usage_fmt[] = {
5498 'F','i','l','e','U','s','a','g','e','=','1',0};
5499
5500 desc = MSI_RecordGetString(rec, 3);
5501
5502 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5503 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5504
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005505 if (!driver_file)
James Hawkinsd3bec322006-11-27 18:20:33 -08005506 {
5507 ERR("ODBC Driver entry not found!\n");
5508 return ERROR_FUNCTION_FAILED;
5509 }
5510
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005511 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5512 if (setup_file)
5513 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
Hans Leidekker587e1072010-02-22 12:26:09 +01005514 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005515
James Hawkinsd3bec322006-11-27 18:20:33 -08005516 driver = msi_alloc(len * sizeof(WCHAR));
5517 if (!driver)
5518 return ERROR_OUTOFMEMORY;
5519
5520 ptr = driver;
5521 lstrcpyW(ptr, desc);
5522 ptr += lstrlenW(ptr) + 1;
5523
Hans Leidekker587e1072010-02-22 12:26:09 +01005524 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5525 ptr += len + 1;
James Hawkinsd3bec322006-11-27 18:20:33 -08005526
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005527 if (setup_file)
5528 {
Hans Leidekker587e1072010-02-22 12:26:09 +01005529 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5530 ptr += len + 1;
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005531 }
James Hawkinsd3bec322006-11-27 18:20:33 -08005532
5533 lstrcpyW(ptr, usage_fmt);
5534 ptr += lstrlenW(ptr) + 1;
5535 *ptr = '\0';
5536
5537 driver_path = strdupW(driver_file->TargetPath);
5538 ptr = strrchrW(driver_path, '\\');
5539 if (ptr) *ptr = '\0';
5540
5541 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5542 NULL, ODBC_INSTALL_COMPLETE, &usage))
5543 {
5544 ERR("Failed to install SQL driver!\n");
5545 r = ERROR_FUNCTION_FAILED;
5546 }
5547
Hans Leidekkereff05032010-03-05 12:25:55 +01005548 uirow = MSI_CreateRecord( 5 );
5549 MSI_RecordSetStringW( uirow, 1, desc );
5550 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5551 MSI_RecordSetStringW( uirow, 3, driver_path );
5552 ui_actiondata( package, szInstallODBC, uirow );
5553 msiobj_release( &uirow->hdr );
5554
James Hawkinsd3bec322006-11-27 18:20:33 -08005555 msi_free(driver);
5556 msi_free(driver_path);
5557
5558 return r;
5559}
5560
Hans Leidekker33c025b2007-04-22 11:37:51 +02005561static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5562{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005563 MSIPACKAGE *package = param;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005564 LPWSTR translator, translator_path, ptr;
5565 WCHAR outpath[MAX_PATH];
5566 MSIFILE *translator_file, *setup_file;
Hans Leidekkereff05032010-03-05 12:25:55 +01005567 MSIRECORD *uirow;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005568 LPCWSTR desc;
5569 DWORD len, usage;
5570 UINT r = ERROR_SUCCESS;
5571
5572 static const WCHAR translator_fmt[] = {
5573 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5574 static const WCHAR setup_fmt[] = {
5575 'S','e','t','u','p','=','%','s',0};
5576
5577 desc = MSI_RecordGetString(rec, 3);
5578
5579 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5580 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5581
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005582 if (!translator_file)
Hans Leidekker33c025b2007-04-22 11:37:51 +02005583 {
5584 ERR("ODBC Translator entry not found!\n");
5585 return ERROR_FUNCTION_FAILED;
5586 }
5587
Hans Leidekker587e1072010-02-22 12:26:09 +01005588 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005589 if (setup_file)
5590 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5591
Hans Leidekker33c025b2007-04-22 11:37:51 +02005592 translator = msi_alloc(len * sizeof(WCHAR));
5593 if (!translator)
5594 return ERROR_OUTOFMEMORY;
5595
5596 ptr = translator;
5597 lstrcpyW(ptr, desc);
5598 ptr += lstrlenW(ptr) + 1;
5599
Hans Leidekker587e1072010-02-22 12:26:09 +01005600 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5601 ptr += len + 1;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005602
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005603 if (setup_file)
5604 {
Hans Leidekker587e1072010-02-22 12:26:09 +01005605 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5606 ptr += len + 1;
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005607 }
Hans Leidekker33c025b2007-04-22 11:37:51 +02005608 *ptr = '\0';
5609
5610 translator_path = strdupW(translator_file->TargetPath);
5611 ptr = strrchrW(translator_path, '\\');
5612 if (ptr) *ptr = '\0';
5613
5614 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5615 NULL, ODBC_INSTALL_COMPLETE, &usage))
5616 {
5617 ERR("Failed to install SQL translator!\n");
5618 r = ERROR_FUNCTION_FAILED;
5619 }
5620
Hans Leidekkereff05032010-03-05 12:25:55 +01005621 uirow = MSI_CreateRecord( 5 );
5622 MSI_RecordSetStringW( uirow, 1, desc );
5623 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5624 MSI_RecordSetStringW( uirow, 3, translator_path );
5625 ui_actiondata( package, szInstallODBC, uirow );
5626 msiobj_release( &uirow->hdr );
5627
Hans Leidekker33c025b2007-04-22 11:37:51 +02005628 msi_free(translator);
5629 msi_free(translator_path);
5630
5631 return r;
5632}
5633
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005634static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5635{
Hans Leidekkereff05032010-03-05 12:25:55 +01005636 MSIPACKAGE *package = param;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005637 LPWSTR attrs;
5638 LPCWSTR desc, driver;
5639 WORD request = ODBC_ADD_SYS_DSN;
5640 INT registration;
5641 DWORD len;
5642 UINT r = ERROR_SUCCESS;
Hans Leidekkereff05032010-03-05 12:25:55 +01005643 MSIRECORD *uirow;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005644
5645 static const WCHAR attrs_fmt[] = {
5646 'D','S','N','=','%','s',0 };
5647
5648 desc = MSI_RecordGetString(rec, 3);
5649 driver = MSI_RecordGetString(rec, 4);
5650 registration = MSI_RecordGetInteger(rec, 5);
5651
5652 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5653 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5654
Hans Leidekker587e1072010-02-22 12:26:09 +01005655 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005656 attrs = msi_alloc(len * sizeof(WCHAR));
5657 if (!attrs)
5658 return ERROR_OUTOFMEMORY;
5659
Hans Leidekker2568e5e2010-02-11 13:13:19 +01005660 len = sprintfW(attrs, attrs_fmt, desc);
5661 attrs[len + 1] = 0;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005662
5663 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5664 {
5665 ERR("Failed to install SQL data source!\n");
5666 r = ERROR_FUNCTION_FAILED;
5667 }
5668
Hans Leidekkereff05032010-03-05 12:25:55 +01005669 uirow = MSI_CreateRecord( 5 );
5670 MSI_RecordSetStringW( uirow, 1, desc );
5671 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5672 MSI_RecordSetInteger( uirow, 3, request );
5673 ui_actiondata( package, szInstallODBC, uirow );
5674 msiobj_release( &uirow->hdr );
5675
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005676 msi_free(attrs);
5677
5678 return r;
5679}
5680
James Hawkinsd3bec322006-11-27 18:20:33 -08005681static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5682{
5683 UINT rc;
5684 MSIQUERY *view;
5685
Hans Leidekker33c025b2007-04-22 11:37:51 +02005686 static const WCHAR driver_query[] = {
James Hawkinsd3bec322006-11-27 18:20:33 -08005687 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5688 'O','D','B','C','D','r','i','v','e','r',0 };
5689
Hans Leidekker33c025b2007-04-22 11:37:51 +02005690 static const WCHAR translator_query[] = {
5691 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5692 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5693
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005694 static const WCHAR source_query[] = {
5695 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5696 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5697
Hans Leidekker33c025b2007-04-22 11:37:51 +02005698 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
James Hawkinsd3bec322006-11-27 18:20:33 -08005699 if (rc != ERROR_SUCCESS)
5700 return ERROR_SUCCESS;
5701
5702 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5703 msiobj_release(&view->hdr);
5704
Hans Leidekker33c025b2007-04-22 11:37:51 +02005705 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5706 if (rc != ERROR_SUCCESS)
5707 return ERROR_SUCCESS;
5708
5709 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5710 msiobj_release(&view->hdr);
5711
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005712 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5713 if (rc != ERROR_SUCCESS)
5714 return ERROR_SUCCESS;
5715
5716 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5717 msiobj_release(&view->hdr);
5718
James Hawkinsd3bec322006-11-27 18:20:33 -08005719 return rc;
5720}
5721
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005722static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5723{
Hans Leidekkera5549302010-03-05 12:26:21 +01005724 MSIPACKAGE *package = param;
5725 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005726 DWORD usage;
5727 LPCWSTR desc;
5728
5729 desc = MSI_RecordGetString( rec, 3 );
5730 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5731 {
5732 WARN("Failed to remove ODBC driver\n");
5733 }
5734 else if (!usage)
5735 {
5736 FIXME("Usage count reached 0\n");
5737 }
5738
Hans Leidekkera5549302010-03-05 12:26:21 +01005739 uirow = MSI_CreateRecord( 2 );
5740 MSI_RecordSetStringW( uirow, 1, desc );
5741 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5742 ui_actiondata( package, szRemoveODBC, uirow );
5743 msiobj_release( &uirow->hdr );
5744
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005745 return ERROR_SUCCESS;
5746}
5747
5748static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5749{
Hans Leidekkera5549302010-03-05 12:26:21 +01005750 MSIPACKAGE *package = param;
5751 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005752 DWORD usage;
5753 LPCWSTR desc;
5754
5755 desc = MSI_RecordGetString( rec, 3 );
5756 if (!SQLRemoveTranslatorW( desc, &usage ))
5757 {
5758 WARN("Failed to remove ODBC translator\n");
5759 }
5760 else if (!usage)
5761 {
5762 FIXME("Usage count reached 0\n");
5763 }
5764
Hans Leidekkera5549302010-03-05 12:26:21 +01005765 uirow = MSI_CreateRecord( 2 );
5766 MSI_RecordSetStringW( uirow, 1, desc );
5767 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5768 ui_actiondata( package, szRemoveODBC, uirow );
5769 msiobj_release( &uirow->hdr );
5770
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005771 return ERROR_SUCCESS;
5772}
5773
5774static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
5775{
Hans Leidekkera5549302010-03-05 12:26:21 +01005776 MSIPACKAGE *package = param;
5777 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005778 LPWSTR attrs;
5779 LPCWSTR desc, driver;
5780 WORD request = ODBC_REMOVE_SYS_DSN;
5781 INT registration;
5782 DWORD len;
5783
5784 static const WCHAR attrs_fmt[] = {
5785 'D','S','N','=','%','s',0 };
5786
5787 desc = MSI_RecordGetString( rec, 3 );
5788 driver = MSI_RecordGetString( rec, 4 );
5789 registration = MSI_RecordGetInteger( rec, 5 );
5790
5791 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
5792 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
5793
Hans Leidekker587e1072010-02-22 12:26:09 +01005794 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005795 attrs = msi_alloc( len * sizeof(WCHAR) );
5796 if (!attrs)
5797 return ERROR_OUTOFMEMORY;
5798
5799 FIXME("Use ODBCSourceAttribute table\n");
5800
5801 len = sprintfW( attrs, attrs_fmt, desc );
5802 attrs[len + 1] = 0;
5803
5804 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
5805 {
5806 WARN("Failed to remove ODBC data source\n");
5807 }
5808 msi_free( attrs );
5809
Hans Leidekkera5549302010-03-05 12:26:21 +01005810 uirow = MSI_CreateRecord( 3 );
5811 MSI_RecordSetStringW( uirow, 1, desc );
5812 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5813 MSI_RecordSetInteger( uirow, 3, request );
5814 ui_actiondata( package, szRemoveODBC, uirow );
5815 msiobj_release( &uirow->hdr );
5816
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005817 return ERROR_SUCCESS;
5818}
5819
5820static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5821{
5822 UINT rc;
5823 MSIQUERY *view;
5824
5825 static const WCHAR driver_query[] = {
5826 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5827 'O','D','B','C','D','r','i','v','e','r',0 };
5828
5829 static const WCHAR translator_query[] = {
5830 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5831 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5832
5833 static const WCHAR source_query[] = {
5834 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5835 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5836
5837 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
5838 if (rc != ERROR_SUCCESS)
5839 return ERROR_SUCCESS;
5840
5841 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
5842 msiobj_release( &view->hdr );
5843
5844 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
5845 if (rc != ERROR_SUCCESS)
5846 return ERROR_SUCCESS;
5847
5848 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
5849 msiobj_release( &view->hdr );
5850
5851 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
5852 if (rc != ERROR_SUCCESS)
5853 return ERROR_SUCCESS;
5854
5855 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
5856 msiobj_release( &view->hdr );
5857
5858 return rc;
5859}
5860
James Hawkins5b8641a2007-05-30 10:57:31 -07005861#define ENV_ACT_SETALWAYS 0x1
5862#define ENV_ACT_SETABSENT 0x2
5863#define ENV_ACT_REMOVE 0x4
James Hawkins881f5922007-06-13 17:46:09 -07005864#define ENV_ACT_REMOVEMATCH 0x8
James Hawkins5b8641a2007-05-30 10:57:31 -07005865
5866#define ENV_MOD_MACHINE 0x20000000
5867#define ENV_MOD_APPEND 0x40000000
5868#define ENV_MOD_PREFIX 0x80000000
James Hawkins881f5922007-06-13 17:46:09 -07005869#define ENV_MOD_MASK 0xC0000000
5870
5871#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5872
Hans Leidekkerf6221112010-03-03 14:38:06 +01005873static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
James Hawkins881f5922007-06-13 17:46:09 -07005874{
5875 LPCWSTR cptr = *name;
James Hawkins881f5922007-06-13 17:46:09 -07005876
5877 static const WCHAR prefix[] = {'[','~',']',0};
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005878 static const int prefix_len = 3;
James Hawkins881f5922007-06-13 17:46:09 -07005879
5880 *flags = 0;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005881 while (*cptr)
James Hawkins881f5922007-06-13 17:46:09 -07005882 {
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005883 if (*cptr == '=')
James Hawkins881f5922007-06-13 17:46:09 -07005884 *flags |= ENV_ACT_SETALWAYS;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005885 else if (*cptr == '+')
James Hawkins881f5922007-06-13 17:46:09 -07005886 *flags |= ENV_ACT_SETABSENT;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005887 else if (*cptr == '-')
James Hawkins881f5922007-06-13 17:46:09 -07005888 *flags |= ENV_ACT_REMOVE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005889 else if (*cptr == '!')
James Hawkins881f5922007-06-13 17:46:09 -07005890 *flags |= ENV_ACT_REMOVEMATCH;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005891 else if (*cptr == '*')
James Hawkins881f5922007-06-13 17:46:09 -07005892 *flags |= ENV_MOD_MACHINE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005893 else
James Hawkins881f5922007-06-13 17:46:09 -07005894 break;
James Hawkins881f5922007-06-13 17:46:09 -07005895
5896 cptr++;
5897 (*name)++;
5898 }
5899
5900 if (!*cptr)
5901 {
5902 ERR("Missing environment variable\n");
5903 return ERROR_FUNCTION_FAILED;
5904 }
5905
Hans Leidekkere52531a2009-11-13 11:06:12 +01005906 if (*value)
James Hawkins881f5922007-06-13 17:46:09 -07005907 {
Hans Leidekkere52531a2009-11-13 11:06:12 +01005908 LPCWSTR ptr = *value;
5909 if (!strncmpW(ptr, prefix, prefix_len))
James Hawkins881f5922007-06-13 17:46:09 -07005910 {
Jason Edmeades06c45a82010-01-20 09:40:37 +00005911 if (ptr[prefix_len] == szSemiColon[0])
5912 {
5913 *flags |= ENV_MOD_APPEND;
5914 *value += lstrlenW(prefix);
5915 }
5916 else
5917 {
5918 *value = NULL;
5919 }
Hans Leidekkere52531a2009-11-13 11:06:12 +01005920 }
5921 else if (lstrlenW(*value) >= prefix_len)
5922 {
5923 ptr += lstrlenW(ptr) - prefix_len;
5924 if (!lstrcmpW(ptr, prefix))
5925 {
Jason Edmeades06c45a82010-01-20 09:40:37 +00005926 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
5927 {
5928 *flags |= ENV_MOD_PREFIX;
5929 /* the "[~]" will be removed by deformat_string */;
5930 }
5931 else
5932 {
5933 *value = NULL;
5934 }
Hans Leidekkere52531a2009-11-13 11:06:12 +01005935 }
James Hawkins881f5922007-06-13 17:46:09 -07005936 }
5937 }
5938
Hans Leidekker659768e2009-09-15 20:52:39 +02005939 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
James Hawkins881f5922007-06-13 17:46:09 -07005940 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5941 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5942 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5943 {
5944 ERR("Invalid flags: %08x\n", *flags);
5945 return ERROR_FUNCTION_FAILED;
5946 }
5947
Hans Leidekker659768e2009-09-15 20:52:39 +02005948 if (!*flags)
5949 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
5950
James Hawkins881f5922007-06-13 17:46:09 -07005951 return ERROR_SUCCESS;
5952}
James Hawkins5b8641a2007-05-30 10:57:31 -07005953
Hans Leidekkerf6221112010-03-03 14:38:06 +01005954static UINT open_env_key( DWORD flags, HKEY *key )
James Hawkins5b8641a2007-05-30 10:57:31 -07005955{
James Hawkins9d712382007-11-05 04:47:12 -05005956 static const WCHAR user_env[] =
5957 {'E','n','v','i','r','o','n','m','e','n','t',0};
5958 static const WCHAR machine_env[] =
James Hawkins5b8641a2007-05-30 10:57:31 -07005959 {'S','y','s','t','e','m','\\',
5960 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5961 'C','o','n','t','r','o','l','\\',
5962 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5963 'E','n','v','i','r','o','n','m','e','n','t',0};
Hans Leidekkerf6221112010-03-03 14:38:06 +01005964 const WCHAR *env;
5965 HKEY root;
5966 LONG res;
5967
5968 if (flags & ENV_MOD_MACHINE)
5969 {
5970 env = machine_env;
5971 root = HKEY_LOCAL_MACHINE;
5972 }
5973 else
5974 {
5975 env = user_env;
5976 root = HKEY_CURRENT_USER;
5977 }
5978
5979 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
5980 if (res != ERROR_SUCCESS)
5981 {
5982 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
5983 return ERROR_FUNCTION_FAILED;
5984 }
5985
5986 return ERROR_SUCCESS;
5987}
5988
5989static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5990{
5991 MSIPACKAGE *package = param;
5992 LPCWSTR name, value, component;
5993 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
5994 DWORD flags, type, size;
5995 UINT res;
Hans Leidekker353035f2010-03-04 09:17:50 +01005996 HKEY env = NULL;
Hans Leidekkerf6221112010-03-03 14:38:06 +01005997 MSICOMPONENT *comp;
5998 MSIRECORD *uirow;
5999 int action = 0;
James Hawkins5b8641a2007-05-30 10:57:31 -07006000
Hans Leidekkerc8308ef2010-03-02 14:55:31 +01006001 component = MSI_RecordGetString(rec, 4);
6002 comp = get_loaded_component(package, component);
6003 if (!comp)
6004 return ERROR_SUCCESS;
6005
6006 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6007 {
6008 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6009 comp->Action = comp->Installed;
6010 return ERROR_SUCCESS;
6011 }
6012 comp->Action = INSTALLSTATE_LOCAL;
6013
James Hawkins881f5922007-06-13 17:46:09 -07006014 name = MSI_RecordGetString(rec, 2);
6015 value = MSI_RecordGetString(rec, 3);
James Hawkins5b8641a2007-05-30 10:57:31 -07006016
Hans Leidekker659768e2009-09-15 20:52:39 +02006017 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6018
Hans Leidekkerf6221112010-03-03 14:38:06 +01006019 res = env_parse_flags(&name, &value, &flags);
Jason Edmeades06c45a82010-01-20 09:40:37 +00006020 if (res != ERROR_SUCCESS || !value)
James Hawkins881f5922007-06-13 17:46:09 -07006021 goto done;
6022
Hans Leidekkere52531a2009-11-13 11:06:12 +01006023 if (value && !deformat_string(package, value, &deformatted))
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07006024 {
6025 res = ERROR_OUTOFMEMORY;
6026 goto done;
6027 }
6028
James Hawkins881f5922007-06-13 17:46:09 -07006029 value = deformatted;
James Hawkins5b8641a2007-05-30 10:57:31 -07006030
Hans Leidekkerf6221112010-03-03 14:38:06 +01006031 res = open_env_key( flags, &env );
James Hawkins5b8641a2007-05-30 10:57:31 -07006032 if (res != ERROR_SUCCESS)
James Hawkins881f5922007-06-13 17:46:09 -07006033 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07006034
Hans Leidekkerf6221112010-03-03 14:38:06 +01006035 if (flags & ENV_MOD_MACHINE)
6036 action |= 0x20000000;
James Hawkins5b8641a2007-05-30 10:57:31 -07006037
6038 size = 0;
James Hawkins26d541b2009-12-16 19:05:27 -08006039 type = REG_SZ;
James Hawkins881f5922007-06-13 17:46:09 -07006040 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6041 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
James Hawkins31c461e2008-01-05 11:46:09 -06006042 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
James Hawkins881f5922007-06-13 17:46:09 -07006043 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07006044
James Hawkins1b7238a2009-12-15 18:19:19 -08006045 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6046 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006047 action = 0x2;
6048
James Hawkins1b7238a2009-12-15 18:19:19 -08006049 /* Nothing to do. */
6050 if (!value)
6051 {
6052 res = ERROR_SUCCESS;
6053 goto done;
6054 }
6055
Jason Edmeades06c45a82010-01-20 09:40:37 +00006056 /* If we are appending but the string was empty, strip ; */
6057 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6058
James Hawkins1b7238a2009-12-15 18:19:19 -08006059 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6060 newval = strdupW(value);
6061 if (!newval)
6062 {
6063 res = ERROR_OUTOFMEMORY;
6064 goto done;
6065 }
6066 }
6067 else
James Hawkins5b8641a2007-05-30 10:57:31 -07006068 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006069 action = 0x1;
6070
Jason Edmeades06c45a82010-01-20 09:40:37 +00006071 /* Contrary to MSDN, +-variable to [~];path works */
6072 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
James Hawkins5b8641a2007-05-30 10:57:31 -07006073 {
6074 res = ERROR_SUCCESS;
6075 goto done;
6076 }
6077
James Hawkins881f5922007-06-13 17:46:09 -07006078 data = msi_alloc(size);
6079 if (!data)
6080 {
6081 RegCloseKey(env);
6082 return ERROR_OUTOFMEMORY;
6083 }
6084
6085 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6086 if (res != ERROR_SUCCESS)
6087 goto done;
6088
6089 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6090 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006091 action = 0x4;
6092 res = RegDeleteValueW(env, name);
6093 if (res != ERROR_SUCCESS)
6094 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
James Hawkins881f5922007-06-13 17:46:09 -07006095 goto done;
6096 }
6097
James Hawkins1b7238a2009-12-15 18:19:19 -08006098 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6099 if (flags & ENV_MOD_MASK)
6100 {
6101 DWORD mod_size;
6102 int multiplier = 0;
6103 if (flags & ENV_MOD_APPEND) multiplier++;
6104 if (flags & ENV_MOD_PREFIX) multiplier++;
Jason Edmeades06c45a82010-01-20 09:40:37 +00006105 mod_size = lstrlenW(value) * multiplier;
James Hawkins1b7238a2009-12-15 18:19:19 -08006106 size += mod_size * sizeof(WCHAR);
6107 }
6108
6109 newval = msi_alloc(size);
James Hawkins881f5922007-06-13 17:46:09 -07006110 ptr = newval;
6111 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07006112 {
6113 res = ERROR_OUTOFMEMORY;
6114 goto done;
6115 }
6116
James Hawkins1b7238a2009-12-15 18:19:19 -08006117 if (flags & ENV_MOD_PREFIX)
6118 {
James Hawkins881f5922007-06-13 17:46:09 -07006119 lstrcpyW(newval, value);
Jason Edmeades06c45a82010-01-20 09:40:37 +00006120 ptr = newval + lstrlenW(value);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006121 action |= 0x80000000;
James Hawkins5b8641a2007-05-30 10:57:31 -07006122 }
6123
James Hawkins1b7238a2009-12-15 18:19:19 -08006124 lstrcpyW(ptr, data);
6125
6126 if (flags & ENV_MOD_APPEND)
6127 {
James Hawkins1b7238a2009-12-15 18:19:19 -08006128 lstrcatW(newval, value);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006129 action |= 0x40000000;
James Hawkins1b7238a2009-12-15 18:19:19 -08006130 }
James Hawkins5b8641a2007-05-30 10:57:31 -07006131 }
Marcus Meissnere2f79462009-12-22 09:32:03 +01006132 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6133 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006134 if (res)
6135 {
6136 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6137 }
James Hawkins5b8641a2007-05-30 10:57:31 -07006138
6139done:
Hans Leidekkerf6221112010-03-03 14:38:06 +01006140 uirow = MSI_CreateRecord( 3 );
6141 MSI_RecordSetStringW( uirow, 1, name );
6142 MSI_RecordSetStringW( uirow, 2, newval );
6143 MSI_RecordSetInteger( uirow, 3, action );
6144 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6145 msiobj_release( &uirow->hdr );
6146
Andrew Talbot0e4ccb82007-06-23 17:28:50 +01006147 if (env) RegCloseKey(env);
James Hawkins881f5922007-06-13 17:46:09 -07006148 msi_free(deformatted);
6149 msi_free(data);
6150 msi_free(newval);
James Hawkins5b8641a2007-05-30 10:57:31 -07006151 return res;
6152}
6153
6154static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6155{
6156 UINT rc;
6157 MSIQUERY * view;
6158 static const WCHAR ExecSeqQuery[] =
6159 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6160 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6161 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6162 if (rc != ERROR_SUCCESS)
6163 return ERROR_SUCCESS;
6164
6165 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6166 msiobj_release(&view->hdr);
6167
6168 return rc;
6169}
6170
Hans Leidekkerf6221112010-03-03 14:38:06 +01006171static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6172{
6173 MSIPACKAGE *package = param;
6174 LPCWSTR name, value, component;
6175 LPWSTR deformatted = NULL;
6176 DWORD flags;
6177 HKEY env;
6178 MSICOMPONENT *comp;
6179 MSIRECORD *uirow;
6180 int action = 0;
6181 LONG res;
6182 UINT r;
6183
6184 component = MSI_RecordGetString( rec, 4 );
6185 comp = get_loaded_component( package, component );
6186 if (!comp)
6187 return ERROR_SUCCESS;
6188
6189 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6190 {
6191 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6192 comp->Action = comp->Installed;
6193 return ERROR_SUCCESS;
6194 }
6195 comp->Action = INSTALLSTATE_ABSENT;
6196
6197 name = MSI_RecordGetString( rec, 2 );
6198 value = MSI_RecordGetString( rec, 3 );
6199
6200 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6201
6202 r = env_parse_flags( &name, &value, &flags );
6203 if (r != ERROR_SUCCESS)
6204 return r;
6205
6206 if (!(flags & ENV_ACT_REMOVE))
6207 {
6208 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6209 return ERROR_SUCCESS;
6210 }
6211
6212 if (value && !deformat_string( package, value, &deformatted ))
6213 return ERROR_OUTOFMEMORY;
6214
6215 value = deformatted;
6216
6217 r = open_env_key( flags, &env );
6218 if (r != ERROR_SUCCESS)
6219 {
6220 r = ERROR_SUCCESS;
6221 goto done;
6222 }
6223
6224 if (flags & ENV_MOD_MACHINE)
6225 action |= 0x20000000;
6226
6227 TRACE("Removing %s\n", debugstr_w(name));
6228
6229 res = RegDeleteValueW( env, name );
6230 if (res != ERROR_SUCCESS)
6231 {
6232 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6233 r = ERROR_SUCCESS;
6234 }
6235
6236done:
6237 uirow = MSI_CreateRecord( 3 );
6238 MSI_RecordSetStringW( uirow, 1, name );
6239 MSI_RecordSetStringW( uirow, 2, value );
6240 MSI_RecordSetInteger( uirow, 3, action );
6241 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6242 msiobj_release( &uirow->hdr );
6243
6244 if (env) RegCloseKey( env );
6245 msi_free( deformatted );
6246 return r;
6247}
6248
6249static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6250{
6251 UINT rc;
6252 MSIQUERY *view;
6253 static const WCHAR query[] =
6254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6255 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6256
6257 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6258 if (rc != ERROR_SUCCESS)
6259 return ERROR_SUCCESS;
6260
6261 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6262 msiobj_release( &view->hdr );
6263
6264 return rc;
6265}
6266
James Hawkins74239fc2008-08-18 22:59:44 -05006267typedef struct tagMSIASSEMBLY
6268{
6269 struct list entry;
6270 MSICOMPONENT *component;
6271 MSIFEATURE *feature;
6272 MSIFILE *file;
6273 LPWSTR manifest;
6274 LPWSTR application;
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006275 LPWSTR display_name;
James Hawkins74239fc2008-08-18 22:59:44 -05006276 DWORD attributes;
6277 BOOL installed;
6278} MSIASSEMBLY;
6279
James Hawkinsbfe07d12008-04-30 04:22:46 -05006280static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6281 DWORD dwReserved);
6282static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6283 LPVOID pvReserved, HMODULE *phModDll);
6284
6285static BOOL init_functionpointers(void)
6286{
6287 HRESULT hr;
6288 HMODULE hfusion;
6289 HMODULE hmscoree;
6290
6291 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6292
6293 hmscoree = LoadLibraryA("mscoree.dll");
6294 if (!hmscoree)
6295 {
6296 WARN("mscoree.dll not available\n");
6297 return FALSE;
6298 }
6299
6300 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6301 if (!pLoadLibraryShim)
6302 {
6303 WARN("LoadLibraryShim not available\n");
6304 FreeLibrary(hmscoree);
6305 return FALSE;
6306 }
6307
6308 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6309 if (FAILED(hr))
6310 {
6311 WARN("fusion.dll not available\n");
6312 FreeLibrary(hmscoree);
6313 return FALSE;
6314 }
6315
6316 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6317
6318 FreeLibrary(hmscoree);
6319 return TRUE;
6320}
6321
James Hawkinsd596ae22008-08-25 00:07:18 -05006322static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6323 LPWSTR path)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006324{
6325 IAssemblyCache *cache;
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006326 MSIRECORD *uirow;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006327 HRESULT hr;
6328 UINT r = ERROR_FUNCTION_FAILED;
6329
James Hawkins74239fc2008-08-18 22:59:44 -05006330 TRACE("installing assembly: %s\n", debugstr_w(path));
6331
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006332 uirow = MSI_CreateRecord( 2 );
6333 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6334 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6335 msiobj_release( &uirow->hdr );
6336
James Hawkins74239fc2008-08-18 22:59:44 -05006337 if (assembly->feature)
James Hawkinsd596ae22008-08-25 00:07:18 -05006338 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
James Hawkins74239fc2008-08-18 22:59:44 -05006339
6340 if (assembly->manifest)
6341 FIXME("Manifest unhandled\n");
6342
6343 if (assembly->application)
6344 {
6345 FIXME("Assembly should be privately installed\n");
6346 return ERROR_SUCCESS;
6347 }
6348
6349 if (assembly->attributes == msidbAssemblyAttributesWin32)
6350 {
6351 FIXME("Win32 assemblies not handled\n");
6352 return ERROR_SUCCESS;
6353 }
6354
James Hawkinsbfe07d12008-04-30 04:22:46 -05006355 hr = pCreateAssemblyCache(&cache, 0);
6356 if (FAILED(hr))
6357 goto done;
6358
6359 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6360 if (FAILED(hr))
6361 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6362
6363 r = ERROR_SUCCESS;
6364
6365done:
6366 IAssemblyCache_Release(cache);
6367 return r;
6368}
6369
James Hawkins74239fc2008-08-18 22:59:44 -05006370typedef struct tagASSEMBLY_LIST
James Hawkinsbfe07d12008-04-30 04:22:46 -05006371{
James Hawkins74239fc2008-08-18 22:59:44 -05006372 MSIPACKAGE *package;
James Hawkins019f4af2008-10-29 03:18:14 -05006373 IAssemblyCache *cache;
James Hawkins74239fc2008-08-18 22:59:44 -05006374 struct list *assemblies;
6375} ASSEMBLY_LIST;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006376
James Hawkins019f4af2008-10-29 03:18:14 -05006377typedef struct tagASSEMBLY_NAME
6378{
6379 LPWSTR name;
6380 LPWSTR version;
6381 LPWSTR culture;
6382 LPWSTR pubkeytoken;
6383} ASSEMBLY_NAME;
6384
6385static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6386{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006387 ASSEMBLY_NAME *asmname = param;
James Hawkins019f4af2008-10-29 03:18:14 -05006388 LPCWSTR name = MSI_RecordGetString(rec, 2);
6389 LPWSTR val = msi_dup_record_field(rec, 3);
6390
6391 static const WCHAR Name[] = {'N','a','m','e',0};
6392 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6393 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6394 static const WCHAR PublicKeyToken[] = {
6395 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6396
Hans Leidekker43094e42009-02-19 14:05:25 +01006397 if (!strcmpiW(name, Name))
James Hawkins019f4af2008-10-29 03:18:14 -05006398 asmname->name = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006399 else if (!strcmpiW(name, Version))
James Hawkins019f4af2008-10-29 03:18:14 -05006400 asmname->version = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006401 else if (!strcmpiW(name, Culture))
James Hawkins019f4af2008-10-29 03:18:14 -05006402 asmname->culture = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006403 else if (!strcmpiW(name, PublicKeyToken))
James Hawkins019f4af2008-10-29 03:18:14 -05006404 asmname->pubkeytoken = val;
6405 else
6406 msi_free(val);
6407
6408 return ERROR_SUCCESS;
6409}
6410
6411static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6412{
6413 if (!*str)
6414 {
6415 *size = lstrlenW(append) + 1;
6416 *str = msi_alloc((*size) * sizeof(WCHAR));
6417 lstrcpyW(*str, append);
6418 return;
6419 }
6420
6421 (*size) += lstrlenW(append);
6422 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6423 lstrcatW(*str, append);
6424}
6425
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006426static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
James Hawkins019f4af2008-10-29 03:18:14 -05006427{
James Hawkins019f4af2008-10-29 03:18:14 -05006428 static const WCHAR separator[] = {',',' ',0};
6429 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6430 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006431 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 -05006432 static const WCHAR query[] = {
6433 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6434 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6435 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6436 '=','\'','%','s','\'',0};
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006437 ASSEMBLY_NAME name;
6438 MSIQUERY *view;
6439 LPWSTR display_name;
6440 DWORD size;
6441 UINT r;
James Hawkins019f4af2008-10-29 03:18:14 -05006442
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006443 display_name = NULL;
6444 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
James Hawkins019f4af2008-10-29 03:18:14 -05006445
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006446 r = MSI_OpenQuery( db, &view, query, comp->Component );
James Hawkins019f4af2008-10-29 03:18:14 -05006447 if (r != ERROR_SUCCESS)
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006448 return NULL;
James Hawkins019f4af2008-10-29 03:18:14 -05006449
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006450 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6451 msiobj_release( &view->hdr );
James Hawkins019f4af2008-10-29 03:18:14 -05006452
6453 if (!name.name)
6454 {
6455 ERR("No assembly name specified!\n");
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006456 return NULL;
James Hawkins019f4af2008-10-29 03:18:14 -05006457 }
6458
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006459 append_str( &display_name, &size, name.name );
James Hawkins019f4af2008-10-29 03:18:14 -05006460
6461 if (name.version)
6462 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006463 append_str( &display_name, &size, separator );
6464 append_str( &display_name, &size, Version );
6465 append_str( &display_name, &size, name.version );
James Hawkins019f4af2008-10-29 03:18:14 -05006466 }
James Hawkins019f4af2008-10-29 03:18:14 -05006467 if (name.culture)
6468 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006469 append_str( &display_name, &size, separator );
6470 append_str( &display_name, &size, Culture );
6471 append_str( &display_name, &size, name.culture );
James Hawkins019f4af2008-10-29 03:18:14 -05006472 }
James Hawkins019f4af2008-10-29 03:18:14 -05006473 if (name.pubkeytoken)
6474 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006475 append_str( &display_name, &size, separator );
6476 append_str( &display_name, &size, PublicKeyToken );
6477 append_str( &display_name, &size, name.pubkeytoken );
James Hawkins019f4af2008-10-29 03:18:14 -05006478 }
6479
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006480 msi_free( name.name );
6481 msi_free( name.version );
6482 msi_free( name.culture );
6483 msi_free( name.pubkeytoken );
6484
6485 return display_name;
6486}
6487
6488static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6489{
6490 ASSEMBLY_INFO asminfo;
6491 LPWSTR disp;
6492 BOOL found = FALSE;
6493 HRESULT hr;
6494
6495 disp = get_assembly_display_name( db, comp );
6496 if (!disp)
6497 return FALSE;
6498
6499 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
James Hawkins019f4af2008-10-29 03:18:14 -05006500 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
James Hawkins019f4af2008-10-29 03:18:14 -05006501
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006502 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6503 if (SUCCEEDED(hr))
6504 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
James Hawkins019f4af2008-10-29 03:18:14 -05006505
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006506 msi_free( disp );
James Hawkins019f4af2008-10-29 03:18:14 -05006507 return found;
6508}
6509
James Hawkins74239fc2008-08-18 22:59:44 -05006510static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6511{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006512 ASSEMBLY_LIST *list = param;
James Hawkins74239fc2008-08-18 22:59:44 -05006513 MSIASSEMBLY *assembly;
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006514 LPCWSTR component;
James Hawkins74239fc2008-08-18 22:59:44 -05006515
6516 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6517 if (!assembly)
6518 return ERROR_OUTOFMEMORY;
6519
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006520 component = MSI_RecordGetString(rec, 1);
6521 assembly->component = get_loaded_component(list->package, component);
6522 if (!assembly->component)
6523 return ERROR_SUCCESS;
James Hawkins74239fc2008-08-18 22:59:44 -05006524
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006525 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6526 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006527 {
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006528 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6529 assembly->component->Action = assembly->component->Installed;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006530 return ERROR_SUCCESS;
6531 }
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006532 assembly->component->Action = assembly->component->ActionRequest;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006533
James Hawkins74239fc2008-08-18 22:59:44 -05006534 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6535 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006536
James Hawkins74239fc2008-08-18 22:59:44 -05006537 if (!assembly->file)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006538 {
James Hawkins74239fc2008-08-18 22:59:44 -05006539 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
James Hawkins70cd6bf2008-05-20 00:35:42 -05006540 return ERROR_FUNCTION_FAILED;
6541 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05006542
James Hawkins74239fc2008-08-18 22:59:44 -05006543 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6544 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6545 assembly->attributes = MSI_RecordGetInteger(rec, 5);
Hans Leidekker9c6e6ef2009-03-25 13:52:56 +01006546
6547 if (assembly->application)
6548 {
6549 WCHAR version[24];
6550 DWORD size = sizeof(version)/sizeof(WCHAR);
6551
6552 /* FIXME: we should probably check the manifest file here */
6553
6554 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
Hans Leidekker7d837b92009-05-29 15:13:57 +02006555 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
Hans Leidekker9c6e6ef2009-03-25 13:52:56 +01006556 {
6557 assembly->installed = TRUE;
6558 }
6559 }
6560 else
6561 assembly->installed = check_assembly_installed(list->package->db,
6562 list->cache,
6563 assembly->component);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006564
James Hawkins74239fc2008-08-18 22:59:44 -05006565 list_add_head(list->assemblies, &assembly->entry);
James Hawkins74239fc2008-08-18 22:59:44 -05006566 return ERROR_SUCCESS;
6567}
James Hawkins9460ae32008-05-13 18:24:48 -05006568
James Hawkins74239fc2008-08-18 22:59:44 -05006569static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6570{
James Hawkins019f4af2008-10-29 03:18:14 -05006571 IAssemblyCache *cache = NULL;
James Hawkins74239fc2008-08-18 22:59:44 -05006572 ASSEMBLY_LIST list;
James Hawkins019f4af2008-10-29 03:18:14 -05006573 MSIQUERY *view;
6574 HRESULT hr;
James Hawkins74239fc2008-08-18 22:59:44 -05006575 UINT r;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006576
James Hawkins74239fc2008-08-18 22:59:44 -05006577 static const WCHAR query[] =
6578 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6579 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6580
6581 r = MSI_DatabaseOpenViewW(package->db, query, &view);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006582 if (r != ERROR_SUCCESS)
James Hawkins74239fc2008-08-18 22:59:44 -05006583 return ERROR_SUCCESS;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006584
James Hawkins019f4af2008-10-29 03:18:14 -05006585 hr = pCreateAssemblyCache(&cache, 0);
6586 if (FAILED(hr))
6587 return ERROR_FUNCTION_FAILED;
6588
James Hawkins74239fc2008-08-18 22:59:44 -05006589 list.package = package;
James Hawkins019f4af2008-10-29 03:18:14 -05006590 list.cache = cache;
James Hawkins74239fc2008-08-18 22:59:44 -05006591 list.assemblies = assemblies;
6592
6593 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6594 msiobj_release(&view->hdr);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006595
James Hawkins019f4af2008-10-29 03:18:14 -05006596 IAssemblyCache_Release(cache);
6597
James Hawkinsbfe07d12008-04-30 04:22:46 -05006598 return r;
6599}
6600
James Hawkins74239fc2008-08-18 22:59:44 -05006601static void free_assemblies(struct list *assemblies)
6602{
6603 struct list *item, *cursor;
6604
6605 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6606 {
6607 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6608
6609 list_remove(&assembly->entry);
6610 msi_free(assembly->application);
6611 msi_free(assembly->manifest);
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006612 msi_free(assembly->display_name);
James Hawkins74239fc2008-08-18 22:59:44 -05006613 msi_free(assembly);
6614 }
6615}
6616
6617static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6618{
6619 MSIASSEMBLY *assembly;
6620
6621 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6622 {
6623 if (!lstrcmpW(assembly->file->File, file))
6624 {
6625 *out = assembly;
6626 return TRUE;
6627 }
6628 }
6629
6630 return FALSE;
6631}
6632
6633static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6634 LPWSTR *path, DWORD *attrs, PVOID user)
6635{
6636 MSIASSEMBLY *assembly;
6637 WCHAR temppath[MAX_PATH];
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006638 struct list *assemblies = user;
James Hawkins74239fc2008-08-18 22:59:44 -05006639 UINT r;
6640
6641 if (!find_assembly(assemblies, file, &assembly))
6642 return FALSE;
6643
6644 GetTempPathW(MAX_PATH, temppath);
6645 PathAddBackslashW(temppath);
6646 lstrcatW(temppath, assembly->file->FileName);
6647
6648 if (action == MSICABEXTRACT_BEGINEXTRACT)
6649 {
6650 if (assembly->installed)
6651 return FALSE;
6652
6653 *path = strdupW(temppath);
6654 *attrs = assembly->file->Attributes;
6655 }
6656 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6657 {
6658 assembly->installed = TRUE;
6659
James Hawkinsd596ae22008-08-25 00:07:18 -05006660 r = install_assembly(package, assembly, temppath);
James Hawkins74239fc2008-08-18 22:59:44 -05006661 if (r != ERROR_SUCCESS)
6662 ERR("Failed to install assembly\n");
6663 }
6664
6665 return TRUE;
6666}
6667
James Hawkinsbfe07d12008-04-30 04:22:46 -05006668static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6669{
James Hawkins74239fc2008-08-18 22:59:44 -05006670 UINT r;
6671 struct list assemblies = LIST_INIT(assemblies);
6672 MSIASSEMBLY *assembly;
6673 MSIMEDIAINFO *mi;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006674
James Hawkins019f4af2008-10-29 03:18:14 -05006675 if (!init_functionpointers() || !pCreateAssemblyCache)
6676 return ERROR_FUNCTION_FAILED;
6677
James Hawkins74239fc2008-08-18 22:59:44 -05006678 r = load_assemblies(package, &assemblies);
6679 if (r != ERROR_SUCCESS)
6680 goto done;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006681
James Hawkins74239fc2008-08-18 22:59:44 -05006682 if (list_empty(&assemblies))
6683 goto done;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006684
James Hawkins74239fc2008-08-18 22:59:44 -05006685 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6686 if (!mi)
6687 {
6688 r = ERROR_OUTOFMEMORY;
6689 goto done;
6690 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05006691
James Hawkins74239fc2008-08-18 22:59:44 -05006692 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6693 {
6694 if (assembly->installed && !mi->is_continuous)
6695 continue;
6696
6697 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6698 (assembly->file->IsCompressed && !mi->is_extracted))
6699 {
6700 MSICABDATA data;
6701
6702 r = ready_media(package, assembly->file, mi);
6703 if (r != ERROR_SUCCESS)
6704 {
6705 ERR("Failed to ready media\n");
6706 break;
6707 }
6708
6709 data.mi = mi;
6710 data.package = package;
6711 data.cb = installassembly_cb;
6712 data.user = &assemblies;
6713
6714 if (assembly->file->IsCompressed &&
6715 !msi_cabextract(package, mi, &data))
6716 {
6717 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6718 r = ERROR_FUNCTION_FAILED;
6719 break;
6720 }
6721 }
6722
6723 if (!assembly->file->IsCompressed)
6724 {
James Hawkinsd15fddf2008-10-06 22:26:20 -05006725 LPWSTR source = resolve_file_source(package, assembly->file);
James Hawkins74239fc2008-08-18 22:59:44 -05006726
James Hawkinsd15fddf2008-10-06 22:26:20 -05006727 r = install_assembly(package, assembly, source);
James Hawkins74239fc2008-08-18 22:59:44 -05006728 if (r != ERROR_SUCCESS)
6729 ERR("Failed to install assembly\n");
James Hawkinsd15fddf2008-10-06 22:26:20 -05006730
6731 msi_free(source);
James Hawkins74239fc2008-08-18 22:59:44 -05006732 }
6733
6734 /* FIXME: write Installer assembly reg values */
6735 }
6736
6737done:
6738 free_assemblies(&assemblies);
6739 return r;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006740}
6741
Hans Leidekker068cb122010-02-10 11:55:59 +01006742static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6743{
6744 LPWSTR key, template, id;
6745 UINT r = ERROR_SUCCESS;
6746
6747 id = msi_dup_property( package, szProductID );
6748 if (id)
6749 {
6750 msi_free( id );
6751 return ERROR_SUCCESS;
6752 }
6753 template = msi_dup_property( package, szPIDTemplate );
6754 key = msi_dup_property( package, szPIDKEY );
6755
6756 if (key && template)
6757 {
6758 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6759 r = MSI_SetPropertyW( package, szProductID, key );
6760 }
6761 msi_free( template );
6762 msi_free( key );
6763 return r;
6764}
6765
Hans Leidekker29f47292010-02-03 09:20:22 +01006766static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6767{
6768 TRACE("\n");
6769 package->need_reboot = 1;
6770 return ERROR_SUCCESS;
6771}
6772
Hans Leidekker5df62d02010-02-10 11:54:57 +01006773static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6774{
Hans Leidekkera64372c2010-03-02 14:55:06 +01006775 static const WCHAR szAvailableFreeReg[] =
6776 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
Hans Leidekker31d06642010-03-05 12:23:22 +01006777 MSIRECORD *uirow;
6778 int space = msi_get_property_int( package, szAvailableFreeReg, 0 );
Hans Leidekkera64372c2010-03-02 14:55:06 +01006779
Hans Leidekker31d06642010-03-05 12:23:22 +01006780 TRACE("%p %d kilobytes\n", package, space);
6781
6782 uirow = MSI_CreateRecord( 1 );
6783 MSI_RecordSetInteger( uirow, 1, space );
6784 ui_actiondata( package, szAllocateRegistrySpace, uirow );
6785 msiobj_release( &uirow->hdr );
6786
Hans Leidekker5df62d02010-02-10 11:54:57 +01006787 return ERROR_SUCCESS;
6788}
6789
6790static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6791{
6792 FIXME("%p\n", package);
6793 return ERROR_SUCCESS;
6794}
6795
6796static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6797{
6798 FIXME("%p\n", package);
6799 return ERROR_SUCCESS;
6800}
6801
Mike McCormack2586a092005-09-26 09:56:18 +00006802static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6803 LPCSTR action, LPCWSTR table )
Mike McCormack567f0312005-09-23 11:06:57 +00006804{
6805 static const WCHAR query[] = {
Mike McCormack2586a092005-09-26 09:56:18 +00006806 'S','E','L','E','C','T',' ','*',' ',
6807 'F','R','O','M',' ','`','%','s','`',0 };
Mike McCormack567f0312005-09-23 11:06:57 +00006808 MSIQUERY *view = NULL;
6809 DWORD count = 0;
Mike McCormack2586a092005-09-26 09:56:18 +00006810 UINT r;
Mike McCormack567f0312005-09-23 11:06:57 +00006811
Mike McCormack2586a092005-09-26 09:56:18 +00006812 r = MSI_OpenQuery( package->db, &view, query, table );
6813 if (r == ERROR_SUCCESS)
Mike McCormack567f0312005-09-23 11:06:57 +00006814 {
Mike McCormack2586a092005-09-26 09:56:18 +00006815 r = MSI_IterateRecords(view, &count, NULL, package);
Mike McCormack567f0312005-09-23 11:06:57 +00006816 msiobj_release(&view->hdr);
6817 }
6818
Mike McCormack2586a092005-09-26 09:56:18 +00006819 if (count)
Mike McCormackf1d46462006-10-05 13:41:22 +09006820 FIXME("%s -> %u ignored %s table values\n",
Mike McCormack2586a092005-09-26 09:56:18 +00006821 action, count, debugstr_w(table));
6822
Mike McCormack567f0312005-09-23 11:06:57 +00006823 return ERROR_SUCCESS;
6824}
Mike McCormack94fbe092005-09-23 17:21:10 +00006825
Mike McCormack2586a092005-09-26 09:56:18 +00006826static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6827{
6828 static const WCHAR table[] = { 'P','a','t','c','h',0 };
6829 return msi_unimplemented_action_stub( package, "PatchFiles", table );
6830}
6831
6832static UINT ACTION_BindImage( MSIPACKAGE *package )
6833{
6834 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6835 return msi_unimplemented_action_stub( package, "BindImage", table );
6836}
6837
6838static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6839{
6840 static const WCHAR table[] = {
Hans Leidekker930b5e12010-02-26 14:09:29 +01006841 '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 +00006842 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6843}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00006844
Mike McCormack2586a092005-09-26 09:56:18 +00006845static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6846{
6847 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6848 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6849}
6850
Mike McCormack3b955152005-09-28 18:10:44 +00006851static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6852{
6853 static const WCHAR table[] = {
6854 'M','s','i','A','s','s','e','m','b','l','y',0 };
6855 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6856}
6857
Mike McCormackf24a9e22005-12-31 13:14:23 +01006858static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6859{
6860 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6861 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6862}
6863
Mike McCormack88603662006-03-22 23:01:56 +09006864static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6865{
6866 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6867 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6868}
6869
6870static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6871{
6872 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6873 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6874}
6875
James Hawkins987c2c82007-05-06 20:52:14 -05006876static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6877{
6878 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6879 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6880}
6881
James Hawkins987c2c82007-05-06 20:52:14 -05006882static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6883{
6884 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6885 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6886}
6887
Hans Leidekker552a9c92010-02-03 09:19:56 +01006888static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6889{
6890 static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 };
6891 return msi_unimplemented_action_stub( package, "SetODBCFolders", table );
6892}
6893
James Hawkins987c2c82007-05-06 20:52:14 -05006894static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
6895{
6896 static const WCHAR table[] = { 'A','p','p','I','d',0 };
6897 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
6898}
6899
6900static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
6901{
6902 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
6903 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
6904}
6905
6906static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
6907{
6908 static const WCHAR table[] = { 'M','I','M','E',0 };
6909 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
6910}
6911
6912static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
6913{
6914 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
6915 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
6916}
6917
Hans Leidekker796eed12009-10-15 12:47:48 +02006918typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6919
6920static const struct
6921{
6922 const WCHAR *action;
6923 UINT (*handler)(MSIPACKAGE *);
6924}
6925StandardActions[] =
6926{
Mike McCormack55942702005-10-30 19:23:28 +00006927 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
Mike McCormack3b955152005-09-28 18:10:44 +00006928 { szAppSearch, ACTION_AppSearch },
6929 { szBindImage, ACTION_BindImage },
James Hawkins987c2c82007-05-06 20:52:14 -05006930 { szCCPSearch, ACTION_CCPSearch },
Mike McCormack3b955152005-09-28 18:10:44 +00006931 { szCostFinalize, ACTION_CostFinalize },
6932 { szCostInitialize, ACTION_CostInitialize },
6933 { szCreateFolders, ACTION_CreateFolders },
6934 { szCreateShortcuts, ACTION_CreateShortcuts },
6935 { szDeleteServices, ACTION_DeleteServices },
Hans Leidekker5df62d02010-02-10 11:54:57 +01006936 { szDisableRollback, ACTION_DisableRollback },
Mike McCormack3b955152005-09-28 18:10:44 +00006937 { szDuplicateFiles, ACTION_DuplicateFiles },
6938 { szExecuteAction, ACTION_ExecuteAction },
6939 { szFileCost, ACTION_FileCost },
6940 { szFindRelatedProducts, ACTION_FindRelatedProducts },
6941 { szForceReboot, ACTION_ForceReboot },
Hans Leidekker5df62d02010-02-10 11:54:57 +01006942 { szInstallAdminPackage, ACTION_InstallAdminPackage },
Mike McCormack3b955152005-09-28 18:10:44 +00006943 { szInstallExecute, ACTION_InstallExecute },
6944 { szInstallExecuteAgain, ACTION_InstallExecute },
6945 { szInstallFiles, ACTION_InstallFiles},
6946 { szInstallFinalize, ACTION_InstallFinalize },
6947 { szInstallInitialize, ACTION_InstallInitialize },
James Hawkins987c2c82007-05-06 20:52:14 -05006948 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
Mike McCormack3b955152005-09-28 18:10:44 +00006949 { szInstallValidate, ACTION_InstallValidate },
6950 { szIsolateComponents, ACTION_IsolateComponents },
6951 { szLaunchConditions, ACTION_LaunchConditions },
6952 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6953 { szMoveFiles, ACTION_MoveFiles },
6954 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6955 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
James Hawkinsd3bec322006-11-27 18:20:33 -08006956 { szInstallODBC, ACTION_InstallODBC },
Mike McCormack3b955152005-09-28 18:10:44 +00006957 { szInstallServices, ACTION_InstallServices },
6958 { szPatchFiles, ACTION_PatchFiles },
6959 { szProcessComponents, ACTION_ProcessComponents },
6960 { szPublishComponents, ACTION_PublishComponents },
6961 { szPublishFeatures, ACTION_PublishFeatures },
6962 { szPublishProduct, ACTION_PublishProduct },
6963 { szRegisterClassInfo, ACTION_RegisterClassInfo },
Mike McCormack88603662006-03-22 23:01:56 +09006964 { szRegisterComPlus, ACTION_RegisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00006965 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6966 { szRegisterFonts, ACTION_RegisterFonts },
6967 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6968 { szRegisterProduct, ACTION_RegisterProduct },
6969 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6970 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
James Hawkins987c2c82007-05-06 20:52:14 -05006971 { szRegisterUser, ACTION_RegisterUser },
6972 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
Mike McCormack3b955152005-09-28 18:10:44 +00006973 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
James Hawkins987c2c82007-05-06 20:52:14 -05006974 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6975 { szRemoveFiles, ACTION_RemoveFiles },
6976 { szRemoveFolders, ACTION_RemoveFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00006977 { szRemoveIniValues, ACTION_RemoveIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05006978 { szRemoveODBC, ACTION_RemoveODBC },
6979 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6980 { szRemoveShortcuts, ACTION_RemoveShortcuts },
6981 { szResolveSource, ACTION_ResolveSource },
6982 { szRMCCPSearch, ACTION_RMCCPSearch },
Hans Leidekker29f47292010-02-03 09:20:22 +01006983 { szScheduleReboot, ACTION_ScheduleReboot },
Mike McCormack3b955152005-09-28 18:10:44 +00006984 { szSelfRegModules, ACTION_SelfRegModules },
6985 { szSelfUnregModules, ACTION_SelfUnregModules },
Hans Leidekker552a9c92010-02-03 09:19:56 +01006986 { szSetODBCFolders, ACTION_SetODBCFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00006987 { szStartServices, ACTION_StartServices },
6988 { szStopServices, ACTION_StopServices },
James Hawkins987c2c82007-05-06 20:52:14 -05006989 { szUnpublishComponents, ACTION_UnpublishComponents },
6990 { szUnpublishFeatures, ACTION_UnpublishFeatures },
6991 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6992 { szUnregisterComPlus, ACTION_UnregisterComPlus },
6993 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
Mike McCormack3b955152005-09-28 18:10:44 +00006994 { szUnregisterFonts, ACTION_UnregisterFonts },
James Hawkins987c2c82007-05-06 20:52:14 -05006995 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6996 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6997 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6998 { szValidateProductID, ACTION_ValidateProductID },
Mike McCormack3b955152005-09-28 18:10:44 +00006999 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7000 { szWriteIniValues, ACTION_WriteIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05007001 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7002 { NULL, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00007003};
Andrew Talbot9e85ec32008-04-03 14:50:28 +01007004
7005static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7006 UINT* rc, BOOL force )
7007{
7008 BOOL ret = FALSE;
7009 BOOL run = force;
7010 int i;
7011
7012 if (!run && !package->script->CurrentlyScripting)
7013 run = TRUE;
7014
7015 if (!run)
7016 {
7017 if (strcmpW(action,szInstallFinalize) == 0 ||
7018 strcmpW(action,szInstallExecute) == 0 ||
7019 strcmpW(action,szInstallExecuteAgain) == 0)
7020 run = TRUE;
7021 }
7022
7023 i = 0;
7024 while (StandardActions[i].action != NULL)
7025 {
7026 if (strcmpW(StandardActions[i].action, action)==0)
7027 {
7028 if (!run)
7029 {
7030 ui_actioninfo(package, action, TRUE, 0);
7031 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7032 ui_actioninfo(package, action, FALSE, *rc);
7033 }
7034 else
7035 {
7036 ui_actionstart(package, action);
7037 if (StandardActions[i].handler)
7038 {
7039 *rc = StandardActions[i].handler(package);
7040 }
7041 else
7042 {
7043 FIXME("unhandled standard action %s\n",debugstr_w(action));
7044 *rc = ERROR_SUCCESS;
7045 }
7046 }
7047 ret = TRUE;
7048 break;
7049 }
7050 i++;
7051 }
7052 return ret;
7053}
Hans Leidekker796eed12009-10-15 12:47:48 +02007054
7055UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7056{
7057 UINT rc = ERROR_SUCCESS;
7058 BOOL handled;
7059
7060 TRACE("Performing action (%s)\n", debugstr_w(action));
7061
7062 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7063
7064 if (!handled)
7065 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7066
7067 if (!handled)
7068 {
7069 WARN("unhandled msi action %s\n", debugstr_w(action));
7070 rc = ERROR_FUNCTION_NOT_CALLED;
7071 }
7072
7073 return rc;
7074}
7075
7076UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7077{
7078 UINT rc = ERROR_SUCCESS;
7079 BOOL handled = FALSE;
7080
7081 TRACE("Performing action (%s)\n", debugstr_w(action));
7082
7083 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7084
7085 if (!handled)
7086 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7087
7088 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7089 handled = TRUE;
7090
7091 if (!handled)
7092 {
7093 WARN("unhandled msi action %s\n", debugstr_w(action));
7094 rc = ERROR_FUNCTION_NOT_CALLED;
7095 }
7096
7097 return rc;
7098}
7099
Hans Leidekkera187b432009-10-15 12:49:10 +02007100static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
Hans Leidekker796eed12009-10-15 12:47:48 +02007101{
7102 UINT rc = ERROR_SUCCESS;
Hans Leidekkera187b432009-10-15 12:49:10 +02007103 MSIRECORD *row;
Hans Leidekker796eed12009-10-15 12:47:48 +02007104
7105 static const WCHAR ExecSeqQuery[] =
7106 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7107 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7108 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7109 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7110 static const WCHAR UISeqQuery[] =
7111 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7112 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7113 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7114 ' ', '=',' ','%','i',0};
7115
Hans Leidekkera187b432009-10-15 12:49:10 +02007116 if (needs_ui_sequence(package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007117 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7118 else
7119 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7120
7121 if (row)
7122 {
7123 LPCWSTR action, cond;
7124
7125 TRACE("Running the actions\n");
7126
7127 /* check conditions */
7128 cond = MSI_RecordGetString(row, 2);
7129
7130 /* this is a hack to skip errors in the condition code */
7131 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
Hans Leidekkera187b432009-10-15 12:49:10 +02007132 {
7133 msiobj_release(&row->hdr);
7134 return ERROR_SUCCESS;
7135 }
Hans Leidekker796eed12009-10-15 12:47:48 +02007136
7137 action = MSI_RecordGetString(row, 1);
7138 if (!action)
7139 {
7140 ERR("failed to fetch action\n");
Hans Leidekkera187b432009-10-15 12:49:10 +02007141 msiobj_release(&row->hdr);
7142 return ERROR_FUNCTION_FAILED;
Hans Leidekker796eed12009-10-15 12:47:48 +02007143 }
7144
Hans Leidekkera187b432009-10-15 12:49:10 +02007145 if (needs_ui_sequence(package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007146 rc = ACTION_PerformUIAction(package, action, -1);
7147 else
7148 rc = ACTION_PerformAction(package, action, -1, FALSE);
Hans Leidekkera187b432009-10-15 12:49:10 +02007149
Hans Leidekker796eed12009-10-15 12:47:48 +02007150 msiobj_release(&row->hdr);
7151 }
Hans Leidekker796eed12009-10-15 12:47:48 +02007152
7153 return rc;
7154}
7155
7156/****************************************************
7157 * TOP level entry points
7158 *****************************************************/
7159
7160UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7161 LPCWSTR szCommandLine )
7162{
7163 UINT rc;
Hans Leidekkera187b432009-10-15 12:49:10 +02007164 BOOL ui_exists;
Hans Leidekker796eed12009-10-15 12:47:48 +02007165
7166 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7167 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7168
7169 MSI_SetPropertyW(package, szAction, szInstall);
7170
Hans Leidekker796eed12009-10-15 12:47:48 +02007171 package->script->InWhatSequence = SEQUENCE_INSTALL;
7172
7173 if (szPackagePath)
7174 {
7175 LPWSTR p, dir;
7176 LPCWSTR file;
7177
7178 dir = strdupW(szPackagePath);
7179 p = strrchrW(dir, '\\');
7180 if (p)
7181 {
7182 *(++p) = 0;
7183 file = szPackagePath + (p - dir);
7184 }
7185 else
7186 {
7187 msi_free(dir);
7188 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7189 GetCurrentDirectoryW(MAX_PATH, dir);
7190 lstrcatW(dir, szBackSlash);
7191 file = szPackagePath;
7192 }
7193
7194 msi_free( package->PackagePath );
7195 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7196 if (!package->PackagePath)
7197 {
7198 msi_free(dir);
7199 return ERROR_OUTOFMEMORY;
7200 }
7201
7202 lstrcpyW(package->PackagePath, dir);
7203 lstrcatW(package->PackagePath, file);
7204 msi_free(dir);
7205
7206 msi_set_sourcedir_props(package, FALSE);
7207 }
7208
7209 msi_parse_command_line( package, szCommandLine, FALSE );
7210
7211 msi_apply_transforms( package );
7212 msi_apply_patches( package );
7213
7214 if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
7215 {
7216 TRACE("setting reinstall property\n");
7217 MSI_SetPropertyW( package, szReinstall, szAll );
7218 }
7219
7220 /* properties may have been added by a transform */
7221 msi_clone_properties( package );
7222 msi_set_context( package );
7223
Hans Leidekkere3aa2f32009-10-15 12:48:26 +02007224 if (needs_ui_sequence( package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007225 {
7226 package->script->InWhatSequence |= SEQUENCE_UI;
7227 rc = ACTION_ProcessUISequence(package);
Hans Leidekker796eed12009-10-15 12:47:48 +02007228 ui_exists = ui_sequence_exists(package);
7229 if (rc == ERROR_SUCCESS || !ui_exists)
7230 {
7231 package->script->InWhatSequence |= SEQUENCE_EXEC;
7232 rc = ACTION_ProcessExecSequence(package, ui_exists);
7233 }
7234 }
7235 else
7236 rc = ACTION_ProcessExecSequence(package, FALSE);
7237
7238 package->script->CurrentlyScripting = FALSE;
7239
7240 /* process the ending type action */
7241 if (rc == ERROR_SUCCESS)
Hans Leidekkera187b432009-10-15 12:49:10 +02007242 ACTION_PerformActionSequence(package, -1);
Hans Leidekker796eed12009-10-15 12:47:48 +02007243 else if (rc == ERROR_INSTALL_USEREXIT)
Hans Leidekkera187b432009-10-15 12:49:10 +02007244 ACTION_PerformActionSequence(package, -2);
Hans Leidekker796eed12009-10-15 12:47:48 +02007245 else if (rc == ERROR_INSTALL_SUSPEND)
Hans Leidekkera187b432009-10-15 12:49:10 +02007246 ACTION_PerformActionSequence(package, -4);
Hans Leidekker796eed12009-10-15 12:47:48 +02007247 else /* failed */
Hans Leidekkera187b432009-10-15 12:49:10 +02007248 ACTION_PerformActionSequence(package, -3);
Hans Leidekker796eed12009-10-15 12:47:48 +02007249
7250 /* finish up running custom actions */
7251 ACTION_FinishCustomActions(package);
7252
7253 if (rc == ERROR_SUCCESS && package->need_reboot)
7254 return ERROR_SUCCESS_REBOOT_REQUIRED;
7255
7256 return rc;
7257}