blob: 4b20d747c970a542762ae6bf418bad4a647e7c20 [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/*
49 * Prototypes
50 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +000051static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
52static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
Aric Stewartf8f64402005-03-24 19:03:45 +000053static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
Andrew Talbot9e85ec32008-04-03 14:50:28 +010054static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc, BOOL force);
Aric Stewart90c57392005-01-31 16:23:12 +000055
Aric Stewart401bd3f2004-06-28 20:34:35 +000056/*
57 * consts and values used
58 */
Juan Lang014ad3b2005-03-01 10:41:52 +000059static const WCHAR c_colon[] = {'C',':','\\',0};
Aric Stewartc6689522005-06-17 20:56:55 +000060
Mike McCormack9ba8ba32005-10-30 19:04:26 +000061static const WCHAR szCreateFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000062 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000063static const WCHAR szCostFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000064 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
Aric Stewartc6689522005-06-17 20:56:55 +000065const WCHAR szInstallFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000066 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +000067const WCHAR szDuplicateFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000068 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000069static const WCHAR szWriteRegistryValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000070 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
71 'V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000072static const WCHAR szCostInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000073 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000074static const WCHAR szFileCost[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000075 {'F','i','l','e','C','o','s','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000076static const WCHAR szInstallInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000077 {'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 +000078static const WCHAR szInstallValidate[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000079 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000080static const WCHAR szLaunchConditions[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000081 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000082static const WCHAR szProcessComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000083 {'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 +000084static const WCHAR szRegisterTypeLibraries[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000085 {'R','e','g','i','s','t','e','r','T','y','p','e',
86 'L','i','b','r','a','r','i','e','s',0};
Aric Stewartdb982e22005-06-16 15:51:44 +000087const WCHAR szRegisterClassInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000088 {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
Aric Stewartdb982e22005-06-16 15:51:44 +000089const WCHAR szRegisterProgIdInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000090 {'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 +000091static const WCHAR szCreateShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000092 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000093static const WCHAR szPublishProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000094 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000095static const WCHAR szWriteIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000096 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000097static const WCHAR szSelfRegModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000098 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000099static const WCHAR szPublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000100 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000101static const WCHAR szRegisterProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000102 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000103static const WCHAR szInstallExecute[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000104 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000105static const WCHAR szInstallExecuteAgain[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000106 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
107 'A','g','a','i','n',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000108static const WCHAR szInstallFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000109 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000110static const WCHAR szForceReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000111 {'F','o','r','c','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000112static const WCHAR szResolveSource[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000113 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
Alexandre Julliardb79a53e2006-06-12 13:39:59 +0200114static const WCHAR szAppSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000115 {'A','p','p','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000116static const WCHAR szAllocateRegistrySpace[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000117 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
118 'S','p','a','c','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000119static const WCHAR szBindImage[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000120 {'B','i','n','d','I','m','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000121static const WCHAR szCCPSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000122 {'C','C','P','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000123static const WCHAR szDeleteServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000124 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000125static const WCHAR szDisableRollback[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000126 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000127static const WCHAR szExecuteAction[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000128 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
Aric Stewartdb982e22005-06-16 15:51:44 +0000129const WCHAR szFindRelatedProducts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000130 {'F','i','n','d','R','e','l','a','t','e','d',
131 'P','r','o','d','u','c','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000132static const WCHAR szInstallAdminPackage[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000133 {'I','n','s','t','a','l','l','A','d','m','i','n',
134 'P','a','c','k','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000135static const WCHAR szInstallSFPCatalogFile[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000136 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
137 'F','i','l','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000138static const WCHAR szIsolateComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000139 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000140const WCHAR szMigrateFeatureStates[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000141 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
142 'S','t','a','t','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000143const WCHAR szMoveFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000144 {'M','o','v','e','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000145static const WCHAR szMsiPublishAssemblies[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000146 {'M','s','i','P','u','b','l','i','s','h',
147 'A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000148static const WCHAR szMsiUnpublishAssemblies[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000149 {'M','s','i','U','n','p','u','b','l','i','s','h',
150 'A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000151static const WCHAR szInstallODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000152 {'I','n','s','t','a','l','l','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000153static const WCHAR szInstallServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000154 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000155const WCHAR szPatchFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000156 {'P','a','t','c','h','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000157static const WCHAR szPublishComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000158 {'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 szRegisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000160 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Aric Stewartdb982e22005-06-16 15:51:44 +0000161const WCHAR szRegisterExtensionInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000162 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
163 'I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000164static const WCHAR szRegisterFonts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000165 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
Aric Stewartdb982e22005-06-16 15:51:44 +0000166const WCHAR szRegisterMIMEInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000167 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000168static const WCHAR szRegisterUser[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000169 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000170const WCHAR szRemoveDuplicateFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000171 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
172 'F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000173static const WCHAR szRemoveEnvironmentStrings[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000174 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
175 'S','t','r','i','n','g','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000176const WCHAR szRemoveExistingProducts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000177 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
178 'P','r','o','d','u','c','t','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000179const WCHAR szRemoveFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000180 {'R','e','m','o','v','e','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000181static const WCHAR szRemoveFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000182 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000183static const WCHAR szRemoveIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000184 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000185static const WCHAR szRemoveODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000186 {'R','e','m','o','v','e','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000187static const WCHAR szRemoveRegistryValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000188 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
189 'V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000190static const WCHAR szRemoveShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000191 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000192static const WCHAR szRMCCPSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000193 {'R','M','C','C','P','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000194static const WCHAR szScheduleReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000195 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000196static const WCHAR szSelfUnregModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000197 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000198static const WCHAR szSetODBCFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000199 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000200static const WCHAR szStartServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000201 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000202static const WCHAR szStopServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000203 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000204static const WCHAR szUnpublishComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000205 {'U','n','p','u','b','l','i','s','h',
206 'C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000207static const WCHAR szUnpublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000208 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000209const WCHAR szUnregisterClassInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000210 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
211 'I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000212static const WCHAR szUnregisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000213 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000214const WCHAR szUnregisterExtensionInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000215 {'U','n','r','e','g','i','s','t','e','r',
216 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000217static const WCHAR szUnregisterFonts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000218 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000219const WCHAR szUnregisterMIMEInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000220 {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000221const WCHAR szUnregisterProgIdInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000222 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
223 'I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000224static const WCHAR szUnregisterTypeLibraries[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000225 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
226 'L','i','b','r','a','r','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000227static const WCHAR szValidateProductID[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000228 {'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 +0000229static const WCHAR szWriteEnvironmentStrings[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000230 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
231 'S','t','r','i','n','g','s',0};
Aric Stewart90c57392005-01-31 16:23:12 +0000232
Mike McCormack3b955152005-09-28 18:10:44 +0000233/* action handlers */
234typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
235
Aric Stewart90c57392005-01-31 16:23:12 +0000236struct _actions {
237 LPCWSTR action;
238 STANDARDACTIONHANDLER handler;
239};
240
Aric Stewart2703d712005-06-20 15:33:10 +0000241
242/********************************************************
243 * helper functions
244 ********************************************************/
245
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000246static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
Aric Stewartd2c395a2004-07-06 18:48:15 +0000247{
Aric Stewartd2c395a2004-07-06 18:48:15 +0000248 static const WCHAR Query_t[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000249 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000250 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
251 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
252 ' ','\'','%','s','\'',0};
Robert Shearmand679bc52006-01-23 17:30:31 +0100253 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000254
Mike McCormack0b352c72005-06-02 10:29:57 +0000255 row = MSI_QueryGetRecord( package->db, Query_t, action );
256 if (!row)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000257 return;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000258 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
259 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000260}
261
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000262static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
Aric Stewartd2c395a2004-07-06 18:48:15 +0000263 UINT rc)
264{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000265 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000266 static const WCHAR template_s[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000267 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
268 '%','s', '.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000269 static const WCHAR template_e[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000270 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
271 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
272 '%','i','.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000273 static const WCHAR format[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000274 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000275 WCHAR message[1024];
276 WCHAR timet[0x100];
277
278 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
279 if (start)
280 sprintfW(message,template_s,timet,action);
281 else
282 sprintfW(message,template_e,timet,action,rc);
283
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000284 row = MSI_CreateRecord(1);
285 MSI_RecordSetStringW(row,1,message);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000286
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000287 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
288 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000289}
290
James Hawkinsdc3060c2007-07-16 14:45:29 -0700291UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
Mike McCormacke3452222005-09-28 15:12:32 +0000292{
293 LPCWSTR ptr,ptr2;
294 BOOL quote;
295 DWORD len;
296 LPWSTR prop = NULL, val = NULL;
297
298 if (!szCommandLine)
299 return ERROR_SUCCESS;
300
301 ptr = szCommandLine;
302
303 while (*ptr)
304 {
305 if (*ptr==' ')
306 {
307 ptr++;
308 continue;
309 }
310
311 TRACE("Looking at %s\n",debugstr_w(ptr));
312
313 ptr2 = strchrW(ptr,'=');
314 if (!ptr2)
315 {
316 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
317 break;
318 }
319
320 quote = FALSE;
321
322 len = ptr2-ptr;
323 prop = msi_alloc((len+1)*sizeof(WCHAR));
324 memcpy(prop,ptr,len*sizeof(WCHAR));
325 prop[len]=0;
326 ptr2++;
327
328 len = 0;
329 ptr = ptr2;
330 while (*ptr && (quote || (!quote && *ptr!=' ')))
331 {
332 if (*ptr == '"')
333 quote = !quote;
334 ptr++;
335 len++;
336 }
337
338 if (*ptr2=='"')
339 {
340 ptr2++;
341 len -= 2;
342 }
343 val = msi_alloc((len+1)*sizeof(WCHAR));
344 memcpy(val,ptr2,len*sizeof(WCHAR));
345 val[len] = 0;
346
347 if (lstrlenW(prop) > 0)
348 {
349 TRACE("Found commandline property (%s) = (%s)\n",
350 debugstr_w(prop), debugstr_w(val));
351 MSI_SetPropertyW(package,prop,val);
352 }
353 msi_free(val);
354 msi_free(prop);
355 }
356
357 return ERROR_SUCCESS;
358}
359
Mike McCormack965a72a2005-10-26 12:06:21 +0000360
361static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
362{
Andrew Talbot2e372c02006-09-17 08:52:49 +0100363 LPCWSTR pc;
Mike McCormack965a72a2005-10-26 12:06:21 +0000364 LPWSTR p, *ret = NULL;
365 UINT count = 0;
366
367 if (!str)
368 return ret;
369
370 /* count the number of substrings */
Andrew Talbot2e372c02006-09-17 08:52:49 +0100371 for ( pc = str, count = 0; pc; count++ )
Mike McCormack965a72a2005-10-26 12:06:21 +0000372 {
Andrew Talbot2e372c02006-09-17 08:52:49 +0100373 pc = strchrW( pc, sep );
374 if (pc)
375 pc++;
Mike McCormack965a72a2005-10-26 12:06:21 +0000376 }
377
378 /* allocate space for an array of substring pointers and the substrings */
379 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
380 (lstrlenW(str)+1) * sizeof(WCHAR) );
381 if (!ret)
382 return ret;
383
384 /* copy the string and set the pointers */
385 p = (LPWSTR) &ret[count+1];
386 lstrcpyW( p, str );
387 for( count = 0; (ret[count] = p); count++ )
388 {
389 p = strchrW( p, sep );
390 if (p)
391 *p++ = 0;
392 }
393
394 return ret;
395}
396
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900397static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
398{
399 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
400 LPWSTR prod_code, patch_product;
401 UINT ret;
402
403 prod_code = msi_dup_property( package, szProductCode );
404 patch_product = msi_get_suminfo_product( patch );
405
406 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
407
408 if ( strstrW( patch_product, prod_code ) )
409 ret = ERROR_SUCCESS;
410 else
411 ret = ERROR_FUNCTION_FAILED;
412
413 msi_free( patch_product );
414 msi_free( prod_code );
415
416 return ret;
417}
418
Mike McCormack965a72a2005-10-26 12:06:21 +0000419static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
420 MSIDATABASE *patch_db, LPCWSTR name )
421{
422 UINT ret = ERROR_FUNCTION_FAILED;
423 IStorage *stg = NULL;
424 HRESULT r;
425
426 TRACE("%p %s\n", package, debugstr_w(name) );
427
428 if (*name++ != ':')
429 {
430 ERR("expected a colon in %s\n", debugstr_w(name));
431 return ERROR_FUNCTION_FAILED;
432 }
433
434 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
435 if (SUCCEEDED(r))
436 {
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900437 ret = msi_check_transform_applicable( package, stg );
438 if (ret == ERROR_SUCCESS)
439 msi_table_apply_transform( package->db, stg );
440 else
441 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
Mike McCormack965a72a2005-10-26 12:06:21 +0000442 IStorage_Release( stg );
Mike McCormack965a72a2005-10-26 12:06:21 +0000443 }
444 else
445 ERR("failed to open substorage %s\n", debugstr_w(name));
446
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900447 return ERROR_SUCCESS;
Mike McCormack965a72a2005-10-26 12:06:21 +0000448}
449
450static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
451{
James Hawkins261e1172007-06-15 14:12:13 -0700452 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
453 LPWSTR guid_list, *guids, product_code;
Mike McCormack965a72a2005-10-26 12:06:21 +0000454 UINT i, ret = ERROR_FUNCTION_FAILED;
455
James Hawkins261e1172007-06-15 14:12:13 -0700456 product_code = msi_dup_property( package, szProdCode );
457 if (!product_code)
Mike McCormack965a72a2005-10-26 12:06:21 +0000458 {
James Hawkins261e1172007-06-15 14:12:13 -0700459 /* FIXME: the property ProductCode should be written into the DB somewhere */
460 ERR("no product code to check\n");
Mike McCormack965a72a2005-10-26 12:06:21 +0000461 return ERROR_SUCCESS;
462 }
463
464 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
465 guids = msi_split_string( guid_list, ';' );
466 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
467 {
James Hawkins261e1172007-06-15 14:12:13 -0700468 if (!lstrcmpW( guids[i], product_code ))
Mike McCormack965a72a2005-10-26 12:06:21 +0000469 ret = ERROR_SUCCESS;
470 }
471 msi_free( guids );
472 msi_free( guid_list );
James Hawkins261e1172007-06-15 14:12:13 -0700473 msi_free( product_code );
Mike McCormack965a72a2005-10-26 12:06:21 +0000474
475 return ret;
476}
477
478static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
479{
480 MSISUMMARYINFO *si;
481 LPWSTR str, *substorage;
482 UINT i, r = ERROR_SUCCESS;
483
Mike McCormack7f98f1d2006-10-24 01:11:30 +0900484 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
Mike McCormack965a72a2005-10-26 12:06:21 +0000485 if (!si)
486 return ERROR_FUNCTION_FAILED;
487
488 msi_check_patch_applicable( package, si );
489
490 /* enumerate the substorage */
491 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
492 substorage = msi_split_string( str, ';' );
493 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
494 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
495 msi_free( substorage );
496 msi_free( str );
497
498 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
499
500 msiobj_release( &si->hdr );
501
502 return r;
503}
504
505static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
506{
507 MSIDATABASE *patch_db = NULL;
508 UINT r;
509
510 TRACE("%p %s\n", package, debugstr_w( file ) );
511
512 /* FIXME:
513 * We probably want to make sure we only open a patch collection here.
514 * Patch collections (.msp) and databases (.msi) have different GUIDs
515 * but currently MSI_OpenDatabaseW will accept both.
516 */
517 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
518 if ( r != ERROR_SUCCESS )
519 {
520 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
521 return r;
522 }
523
524 msi_parse_patch_summary( package, patch_db );
Mike McCormack9a4ba8c2006-11-01 15:09:23 +0900525
526 /*
527 * There might be a CAB file in the patch package,
528 * so append it to the list of storage to search for streams.
529 */
530 append_storage_to_db( package->db, patch_db->storage );
531
Mike McCormack965a72a2005-10-26 12:06:21 +0000532 msiobj_release( &patch_db->hdr );
533
534 return ERROR_SUCCESS;
535}
536
537/* get the PATCH property, and apply all the patches it specifies */
538static UINT msi_apply_patches( MSIPACKAGE *package )
539{
540 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
541 LPWSTR patch_list, *patches;
542 UINT i, r = ERROR_SUCCESS;
543
544 patch_list = msi_dup_property( package, szPatch );
545
546 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
547
548 patches = msi_split_string( patch_list, ';' );
549 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
550 r = msi_apply_patch_package( package, patches[i] );
551
552 msi_free( patches );
553 msi_free( patch_list );
554
555 return r;
556}
557
Mike McCormacke534e772006-01-04 14:51:25 +0100558static UINT msi_apply_transforms( MSIPACKAGE *package )
559{
560 static const WCHAR szTransforms[] = {
561 'T','R','A','N','S','F','O','R','M','S',0 };
562 LPWSTR xform_list, *xforms;
563 UINT i, r = ERROR_SUCCESS;
564
565 xform_list = msi_dup_property( package, szTransforms );
566 xforms = msi_split_string( xform_list, ';' );
567
568 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
569 {
570 if (xforms[i][0] == ':')
James Hawkins776a7d72008-03-10 23:03:50 -0500571 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
Mike McCormacke534e772006-01-04 14:51:25 +0100572 else
573 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
574 }
575
576 msi_free( xforms );
577 msi_free( xform_list );
578
579 return r;
580}
581
James Hawkins4439e0b2008-02-29 23:29:43 -0600582static BOOL ui_sequence_exists( MSIPACKAGE *package )
James Hawkins6da80412007-04-15 03:10:58 -0500583{
584 MSIQUERY *view;
585 UINT rc;
586
587 static const WCHAR ExecSeqQuery [] =
588 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
589 '`','I','n','s','t','a','l','l',
590 'U','I','S','e','q','u','e','n','c','e','`',
591 ' ','W','H','E','R','E',' ',
592 '`','S','e','q','u','e','n','c','e','`',' ',
593 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
594 '`','S','e','q','u','e','n','c','e','`',0};
595
596 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
597 if (rc == ERROR_SUCCESS)
598 {
599 msiobj_release(&view->hdr);
600 return TRUE;
601 }
602
603 return FALSE;
604}
605
James Hawkinsc777d302008-01-05 13:45:13 -0700606static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
607{
James Hawkins062070b2008-01-05 13:46:39 -0700608 LPWSTR p, db;
James Hawkinsc777d302008-01-05 13:45:13 -0700609 LPWSTR source, check;
610 DWORD len;
611
James Hawkinsc37849a2008-01-05 13:50:59 -0700612 static const WCHAR szOriginalDatabase[] =
613 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
614
James Hawkins062070b2008-01-05 13:46:39 -0700615 db = msi_dup_property( package, szOriginalDatabase );
616 if (!db)
617 return ERROR_OUTOFMEMORY;
James Hawkinsc777d302008-01-05 13:45:13 -0700618
James Hawkins062070b2008-01-05 13:46:39 -0700619 p = strrchrW( db, '\\' );
620 if (!p)
621 {
James Hawkins18648762008-01-05 13:47:14 -0700622 p = strrchrW( db, '/' );
623 if (!p)
624 {
625 msi_free(db);
626 return ERROR_SUCCESS;
627 }
James Hawkins062070b2008-01-05 13:46:39 -0700628 }
629
630 len = p - db + 2;
James Hawkinsc777d302008-01-05 13:45:13 -0700631 source = msi_alloc( len * sizeof(WCHAR) );
James Hawkins062070b2008-01-05 13:46:39 -0700632 lstrcpynW( source, db, len );
James Hawkinsc777d302008-01-05 13:45:13 -0700633
634 check = msi_dup_property( package, cszSourceDir );
635 if (!check || replace)
636 MSI_SetPropertyW( package, cszSourceDir, source );
637
638 msi_free( check );
639
640 check = msi_dup_property( package, cszSOURCEDIR );
641 if (!check || replace)
642 MSI_SetPropertyW( package, cszSOURCEDIR, source );
643
644 msi_free( check );
645 msi_free( source );
James Hawkins062070b2008-01-05 13:46:39 -0700646 msi_free( db );
James Hawkinsc777d302008-01-05 13:45:13 -0700647
648 return ERROR_SUCCESS;
649}
650
Aric Stewart401bd3f2004-06-28 20:34:35 +0000651/****************************************************
652 * TOP level entry points
653 *****************************************************/
654
Mike McCormack61f24a42005-09-30 10:32:41 +0000655UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
656 LPCWSTR szCommandLine )
Aric Stewart401bd3f2004-06-28 20:34:35 +0000657{
Aric Stewart401bd3f2004-06-28 20:34:35 +0000658 UINT rc;
James Hawkins6da80412007-04-15 03:10:58 -0500659 BOOL ui = FALSE, ui_exists;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000660 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
Aric Stewart6269f002005-01-17 13:40:39 +0000661 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
662 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
663
664 MSI_SetPropertyW(package, szAction, szInstall);
Aric Stewart9cd707d2005-05-27 19:24:22 +0000665
Mike McCormack3a940112006-04-19 02:29:03 +0900666 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
Aric Stewart401bd3f2004-06-28 20:34:35 +0000667
Aric Stewartc9802932005-06-30 20:45:43 +0000668 package->script->InWhatSequence = SEQUENCE_INSTALL;
669
Aric Stewarte95136b2004-06-29 03:44:01 +0000670 if (szPackagePath)
671 {
James Hawkinsc777d302008-01-05 13:45:13 -0700672 LPWSTR p, dir;
Andrew Talbot0e14c292007-07-23 18:53:19 +0100673 LPCWSTR file;
James Hawkins08443b32007-07-02 20:19:46 -0700674
675 dir = strdupW(szPackagePath);
676 p = strrchrW(dir, '\\');
Aric Stewarte95136b2004-06-29 03:44:01 +0000677 if (p)
Andrew Talbot0e14c292007-07-23 18:53:19 +0100678 {
James Hawkins08443b32007-07-02 20:19:46 -0700679 *(++p) = 0;
Andrew Talbot0e14c292007-07-23 18:53:19 +0100680 file = szPackagePath + (p - dir);
681 }
Aric Stewartc1e5c4a2005-02-08 14:26:49 +0000682 else
683 {
James Hawkins08443b32007-07-02 20:19:46 -0700684 msi_free(dir);
685 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
686 GetCurrentDirectoryW(MAX_PATH, dir);
687 lstrcatW(dir, cszbs);
Andrew Talbot0e14c292007-07-23 18:53:19 +0100688 file = szPackagePath;
Aric Stewartc1e5c4a2005-02-08 14:26:49 +0000689 }
Aric Stewarte95136b2004-06-29 03:44:01 +0000690
James Hawkins08443b32007-07-02 20:19:46 -0700691 msi_free( package->PackagePath );
Andrew Talbot0e14c292007-07-23 18:53:19 +0100692 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
James Hawkins08443b32007-07-02 20:19:46 -0700693 if (!package->PackagePath)
694 {
695 msi_free(dir);
696 return ERROR_OUTOFMEMORY;
697 }
698
699 lstrcpyW(package->PackagePath, dir);
Andrew Talbot0e14c292007-07-23 18:53:19 +0100700 lstrcatW(package->PackagePath, file);
James Hawkins08443b32007-07-02 20:19:46 -0700701 msi_free(dir);
James Hawkinsc777d302008-01-05 13:45:13 -0700702
703 msi_set_sourcedir_props(package, FALSE);
Aric Stewarte95136b2004-06-29 03:44:01 +0000704 }
Aric Stewart401bd3f2004-06-28 20:34:35 +0000705
Mike McCormacke3452222005-09-28 15:12:32 +0000706 msi_parse_command_line( package, szCommandLine );
Mike McCormack74f0de92005-09-29 10:32:39 +0000707
Mike McCormacke534e772006-01-04 14:51:25 +0100708 msi_apply_transforms( package );
Mike McCormack965a72a2005-10-26 12:06:21 +0000709 msi_apply_patches( package );
710
James Hawkins30fc5602007-07-12 11:36:43 -0700711 /* properties may have been added by a transform */
712 msi_clone_properties( package );
713
Misha Koshelevd8b00a02007-02-06 23:53:24 -0600714 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000715 {
Mike McCormack74f0de92005-09-29 10:32:39 +0000716 package->script->InWhatSequence |= SEQUENCE_UI;
717 rc = ACTION_ProcessUISequence(package);
718 ui = TRUE;
James Hawkins6da80412007-04-15 03:10:58 -0500719 ui_exists = ui_sequence_exists(package);
720 if (rc == ERROR_SUCCESS || !ui_exists)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000721 {
Mike McCormack74f0de92005-09-29 10:32:39 +0000722 package->script->InWhatSequence |= SEQUENCE_EXEC;
James Hawkins6da80412007-04-15 03:10:58 -0500723 rc = ACTION_ProcessExecSequence(package,ui_exists);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000724 }
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000725 }
726 else
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000727 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000728
Aric Stewart9cd707d2005-05-27 19:24:22 +0000729 package->script->CurrentlyScripting= FALSE;
730
Aric Stewart09d35c32004-12-27 19:00:26 +0000731 /* process the ending type action */
732 if (rc == ERROR_SUCCESS)
Aric Stewartf8f64402005-03-24 19:03:45 +0000733 ACTION_PerformActionSequence(package,-1,ui);
Aric Stewart6b16f292005-01-27 11:12:56 +0000734 else if (rc == ERROR_INSTALL_USEREXIT)
Aric Stewartf8f64402005-03-24 19:03:45 +0000735 ACTION_PerformActionSequence(package,-2,ui);
Aric Stewart6b16f292005-01-27 11:12:56 +0000736 else if (rc == ERROR_INSTALL_SUSPEND)
Aric Stewartf8f64402005-03-24 19:03:45 +0000737 ACTION_PerformActionSequence(package,-4,ui);
Aric Stewart9cd707d2005-05-27 19:24:22 +0000738 else /* failed */
739 ACTION_PerformActionSequence(package,-3,ui);
Aric Stewart54c67dd2005-01-25 20:17:09 +0000740
741 /* finish up running custom actions */
742 ACTION_FinishCustomActions(package);
Aric Stewart09d35c32004-12-27 19:00:26 +0000743
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000744 return rc;
745}
746
Aric Stewartf8f64402005-03-24 19:03:45 +0000747static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
Aric Stewart09d35c32004-12-27 19:00:26 +0000748{
Mike McCormack0b352c72005-06-02 10:29:57 +0000749 UINT rc = ERROR_SUCCESS;
Aric Stewart09d35c32004-12-27 19:00:26 +0000750 MSIRECORD * row = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +0000751 static const WCHAR ExecSeqQuery[] =
752 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000753 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
754 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
755 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
Aric Stewart09d35c32004-12-27 19:00:26 +0000756
Aric Stewartf8f64402005-03-24 19:03:45 +0000757 static const WCHAR UISeqQuery[] =
758 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000759 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
760 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
Aric Stewartf8f64402005-03-24 19:03:45 +0000761 ' ', '=',' ','%','i',0};
762
763 if (UI)
Mike McCormack0b352c72005-06-02 10:29:57 +0000764 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
Aric Stewartf8f64402005-03-24 19:03:45 +0000765 else
Mike McCormack0b352c72005-06-02 10:29:57 +0000766 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
Aric Stewart09d35c32004-12-27 19:00:26 +0000767
Mike McCormack0b352c72005-06-02 10:29:57 +0000768 if (row)
Aric Stewart09d35c32004-12-27 19:00:26 +0000769 {
Mike McCormack20806c72005-06-07 21:34:05 +0000770 LPCWSTR action, cond;
771
Aric Stewart09d35c32004-12-27 19:00:26 +0000772 TRACE("Running the actions\n");
773
Aric Stewart09d35c32004-12-27 19:00:26 +0000774 /* check conditions */
Mike McCormack20806c72005-06-07 21:34:05 +0000775 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900776
777 /* this is a hack to skip errors in the condition code */
778 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
779 goto end;
Aric Stewart09d35c32004-12-27 19:00:26 +0000780
Mike McCormack20806c72005-06-07 21:34:05 +0000781 action = MSI_RecordGetString(row,1);
782 if (!action)
Aric Stewart09d35c32004-12-27 19:00:26 +0000783 {
Mike McCormack20806c72005-06-07 21:34:05 +0000784 ERR("failed to fetch action\n");
785 rc = ERROR_FUNCTION_FAILED;
Aric Stewart09d35c32004-12-27 19:00:26 +0000786 goto end;
787 }
788
Aric Stewartf8f64402005-03-24 19:03:45 +0000789 if (UI)
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100790 rc = ACTION_PerformUIAction(package,action,-1);
Aric Stewartf8f64402005-03-24 19:03:45 +0000791 else
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100792 rc = ACTION_PerformAction(package,action,-1,FALSE);
Aric Stewart09d35c32004-12-27 19:00:26 +0000793end:
Mike McCormack0b352c72005-06-02 10:29:57 +0000794 msiobj_release(&row->hdr);
Aric Stewart09d35c32004-12-27 19:00:26 +0000795 }
796 else
797 rc = ERROR_SUCCESS;
798
799 return rc;
800}
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000801
Aric Stewart2703d712005-06-20 15:33:10 +0000802typedef struct {
803 MSIPACKAGE* package;
804 BOOL UI;
805} iterate_action_param;
806
807static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
808{
809 iterate_action_param *iap= (iterate_action_param*)param;
810 UINT rc;
811 LPCWSTR cond, action;
812
813 action = MSI_RecordGetString(row,1);
814 if (!action)
815 {
816 ERR("Error is retrieving action name\n");
Mike McCormack9375fd92006-10-27 17:29:02 +0900817 return ERROR_FUNCTION_FAILED;
Aric Stewart2703d712005-06-20 15:33:10 +0000818 }
819
820 /* check conditions */
821 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900822
823 /* this is a hack to skip errors in the condition code */
824 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
Aric Stewart2703d712005-06-20 15:33:10 +0000825 {
Mike McCormack9375fd92006-10-27 17:29:02 +0900826 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
827 return ERROR_SUCCESS;
Aric Stewart2703d712005-06-20 15:33:10 +0000828 }
829
830 if (iap->UI)
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100831 rc = ACTION_PerformUIAction(iap->package,action,-1);
Aric Stewart2703d712005-06-20 15:33:10 +0000832 else
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100833 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
Aric Stewart2703d712005-06-20 15:33:10 +0000834
Mike McCormack4f634a32005-07-06 15:44:51 +0000835 msi_dialog_check_messages( NULL );
836
837 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
838 rc = iap->package->CurrentInstallState;
839
Aric Stewart2703d712005-06-20 15:33:10 +0000840 if (rc == ERROR_FUNCTION_NOT_CALLED)
841 rc = ERROR_SUCCESS;
842
843 if (rc != ERROR_SUCCESS)
Mike McCormack558abec2005-10-27 12:39:28 +0000844 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
Aric Stewart2703d712005-06-20 15:33:10 +0000845
846 return rc;
847}
848
Mike McCormackd34b1c22005-09-21 10:55:23 +0000849UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
850{
851 MSIQUERY * view;
852 UINT r;
853 static const WCHAR query[] =
854 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
855 '`','%','s','`',
856 ' ','W','H','E','R','E',' ',
857 '`','S','e','q','u','e','n','c','e','`',' ',
858 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
859 '`','S','e','q','u','e','n','c','e','`',0};
860 iterate_action_param iap;
861
862 /*
863 * FIXME: probably should be checking UILevel in the
864 * ACTION_PerformUIAction/ACTION_PerformAction
865 * rather than saving the UI level here. Those
866 * two functions can be merged too.
867 */
868 iap.package = package;
869 iap.UI = TRUE;
870
871 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
872
873 r = MSI_OpenQuery( package->db, &view, query, szTable );
874 if (r == ERROR_SUCCESS)
875 {
876 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
877 msiobj_release(&view->hdr);
878 }
879
880 return r;
881}
882
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000883static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000884{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000885 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000886 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000887 static const WCHAR ExecSeqQuery[] =
888 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000889 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
890 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
891 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000892 'O','R','D','E','R',' ', 'B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000893 '`','S','e','q','u','e','n','c','e','`',0 };
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000894 MSIRECORD * row = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +0000895 static const WCHAR IVQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +0000896 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
897 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
898 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
899 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
900 ' ','\'', 'I','n','s','t','a','l','l',
901 'V','a','l','i','d','a','t','e','\'', 0};
Mike McCormack9db0e072004-12-22 15:05:07 +0000902 INT seq = 0;
Aric Stewart2703d712005-06-20 15:33:10 +0000903 iterate_action_param iap;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000904
Aric Stewart2703d712005-06-20 15:33:10 +0000905 iap.package = package;
906 iap.UI = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000907
Aric Stewart9cd707d2005-05-27 19:24:22 +0000908 if (package->script->ExecuteSequenceRun)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000909 {
910 TRACE("Execute Sequence already Run\n");
911 return ERROR_SUCCESS;
912 }
913
Aric Stewart9cd707d2005-05-27 19:24:22 +0000914 package->script->ExecuteSequenceRun = TRUE;
Aric Stewart2703d712005-06-20 15:33:10 +0000915
Mike McCormack9db0e072004-12-22 15:05:07 +0000916 /* get the sequence number */
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000917 if (UIran)
918 {
Mike McCormack0b352c72005-06-02 10:29:57 +0000919 row = MSI_QueryGetRecord(package->db, IVQuery);
920 if( !row )
921 return ERROR_FUNCTION_FAILED;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000922 seq = MSI_RecordGetInteger(row,1);
923 msiobj_release(&row->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000924 }
Mike McCormack9db0e072004-12-22 15:05:07 +0000925
Mike McCormack0c238852005-01-21 16:19:11 +0000926 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000927 if (rc == ERROR_SUCCESS)
928 {
Aric Stewart2703d712005-06-20 15:33:10 +0000929 TRACE("Running the actions\n");
Aric Stewart401bd3f2004-06-28 20:34:35 +0000930
Aric Stewart2703d712005-06-20 15:33:10 +0000931 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000932 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000933 }
934
Aric Stewart401bd3f2004-06-28 20:34:35 +0000935 return rc;
936}
937
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000938static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000939{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000940 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000941 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000942 static const WCHAR ExecSeqQuery [] =
943 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000944 '`','I','n','s','t','a','l','l',
945 'U','I','S','e','q','u','e','n','c','e','`',
946 ' ','W','H','E','R','E',' ',
947 '`','S','e','q','u','e','n','c','e','`',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000948 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000949 '`','S','e','q','u','e','n','c','e','`',0};
Aric Stewart2703d712005-06-20 15:33:10 +0000950 iterate_action_param iap;
951
952 iap.package = package;
953 iap.UI = TRUE;
954
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000955 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000956
957 if (rc == ERROR_SUCCESS)
958 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000959 TRACE("Running the actions\n");
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000960
Aric Stewart2703d712005-06-20 15:33:10 +0000961 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000962 msiobj_release(&view->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000963 }
964
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000965 return rc;
966}
967
Aric Stewart401bd3f2004-06-28 20:34:35 +0000968/********************************************************
969 * ACTION helper functions and functions that perform the actions
970 *******************************************************/
Mike McCormackf9acfe62005-06-07 20:29:51 +0000971static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100972 UINT* rc, UINT script, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +0000973{
974 BOOL ret=FALSE;
975 UINT arc;
976
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100977 arc = ACTION_CustomAction(package, action, script, force);
Aric Stewart3f318602005-02-01 18:46:26 +0000978
979 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
980 {
981 *rc = arc;
982 ret = TRUE;
983 }
984 return ret;
985}
Aric Stewart401bd3f2004-06-28 20:34:35 +0000986
987/*
Francois Gougetda8b3dd2005-01-26 21:09:04 +0000988 * A lot of actions are really important even if they don't do anything
989 * explicit... Lots of properties are set at the beginning of the installation
990 * CostFinalize does a bunch of work to translate the directories and such
Aric Stewart401bd3f2004-06-28 20:34:35 +0000991 *
Mike McCormack6e2bca32004-07-04 00:25:00 +0000992 * But until I get write access to the database that is hard, so I am going to
Aric Stewart401bd3f2004-06-28 20:34:35 +0000993 * hack it to see if I can get something to run.
994 */
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100995UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
Aric Stewart401bd3f2004-06-28 20:34:35 +0000996{
Aric Stewartd2c395a2004-07-06 18:48:15 +0000997 UINT rc = ERROR_SUCCESS;
Aric Stewart3f318602005-02-01 18:46:26 +0000998 BOOL handled;
Aric Stewart401bd3f2004-06-28 20:34:35 +0000999
1000 TRACE("Performing action (%s)\n",debugstr_w(action));
1001
Aric Stewart9cd707d2005-05-27 19:24:22 +00001002 handled = ACTION_HandleStandardAction(package, action, &rc, force);
Aric Stewart7d3e5972004-07-04 00:36:58 +00001003
Aric Stewart3f318602005-02-01 18:46:26 +00001004 if (!handled)
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001005 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
Aric Stewart3f318602005-02-01 18:46:26 +00001006
Aric Stewart90c57392005-01-31 16:23:12 +00001007 if (!handled)
1008 {
James Hawkinsc48daf92008-04-02 18:30:37 -05001009 WARN("unhandled msi action %s\n",debugstr_w(action));
Aric Stewart3f318602005-02-01 18:46:26 +00001010 rc = ERROR_FUNCTION_NOT_CALLED;
1011 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00001012
Aric Stewart3f318602005-02-01 18:46:26 +00001013 return rc;
1014}
1015
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001016UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
Aric Stewart3f318602005-02-01 18:46:26 +00001017{
1018 UINT rc = ERROR_SUCCESS;
1019 BOOL handled = FALSE;
1020
1021 TRACE("Performing action (%s)\n",debugstr_w(action));
1022
Aric Stewart9cd707d2005-05-27 19:24:22 +00001023 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
Aric Stewart3f318602005-02-01 18:46:26 +00001024
1025 if (!handled)
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001026 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
Aric Stewart3f318602005-02-01 18:46:26 +00001027
Mike McCormack4f634a32005-07-06 15:44:51 +00001028 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1029 handled = TRUE;
Mike McCormack34d4a022005-02-09 13:24:31 +00001030
Aric Stewart3f318602005-02-01 18:46:26 +00001031 if (!handled)
1032 {
James Hawkinsc48daf92008-04-02 18:30:37 -05001033 WARN("unhandled msi action %s\n",debugstr_w(action));
Aric Stewart3f318602005-02-01 18:46:26 +00001034 rc = ERROR_FUNCTION_NOT_CALLED;
Aric Stewart90c57392005-01-31 16:23:12 +00001035 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00001036
Aric Stewartd2c395a2004-07-06 18:48:15 +00001037 return rc;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001038}
1039
Aric Stewart2274ff12005-06-21 20:03:46 +00001040
1041/*
1042 * Actual Action Handlers
1043 */
1044
1045static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1046{
1047 MSIPACKAGE *package = (MSIPACKAGE*)param;
1048 LPCWSTR dir;
1049 LPWSTR full_path;
1050 MSIRECORD *uirow;
1051 MSIFOLDER *folder;
1052
1053 dir = MSI_RecordGetString(row,1);
1054 if (!dir)
1055 {
Francois Gouget0edbaf72005-11-10 12:14:56 +00001056 ERR("Unable to get folder id\n");
Aric Stewart2274ff12005-06-21 20:03:46 +00001057 return ERROR_SUCCESS;
1058 }
1059
James Hawkins8cedb212007-03-29 02:38:57 -05001060 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
Aric Stewart2274ff12005-06-21 20:03:46 +00001061 if (!full_path)
1062 {
1063 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1064 return ERROR_SUCCESS;
1065 }
1066
1067 TRACE("Folder is %s\n",debugstr_w(full_path));
1068
1069 /* UI stuff */
1070 uirow = MSI_CreateRecord(1);
1071 MSI_RecordSetStringW(uirow,1,full_path);
1072 ui_actiondata(package,szCreateFolders,uirow);
1073 msiobj_release( &uirow->hdr );
1074
1075 if (folder->State == 0)
1076 create_full_pathW(full_path);
1077
1078 folder->State = 3;
1079
Mike McCormackee034ba2005-09-20 11:59:14 +00001080 msi_free(full_path);
Aric Stewart2274ff12005-06-21 20:03:46 +00001081 return ERROR_SUCCESS;
1082}
1083
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001084/* FIXME: probably should merge this with the above function */
1085static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1086{
1087 UINT rc = ERROR_SUCCESS;
1088 MSIFOLDER *folder;
1089 LPWSTR install_path;
1090
James Hawkins8cedb212007-03-29 02:38:57 -05001091 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001092 if (!install_path)
1093 return ERROR_FUNCTION_FAILED;
1094
1095 /* create the path */
1096 if (folder->State == 0)
1097 {
1098 create_full_pathW(install_path);
1099 folder->State = 2;
1100 }
1101 msi_free(install_path);
1102
1103 return rc;
1104}
Aric Stewart2274ff12005-06-21 20:03:46 +00001105
Mike McCormack9c845852005-10-29 11:29:17 +00001106UINT msi_create_component_directories( MSIPACKAGE *package )
1107{
1108 MSICOMPONENT *comp;
1109
1110 /* create all the folders required by the components are going to install */
1111 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1112 {
Mike McCormackd693f462005-10-29 11:36:48 +00001113 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Mike McCormack9c845852005-10-29 11:29:17 +00001114 continue;
1115 msi_create_directory( package, comp->Directory );
1116 }
1117
1118 return ERROR_SUCCESS;
1119}
1120
Aric Stewart401bd3f2004-06-28 20:34:35 +00001121/*
1122 * Also we cannot enable/disable components either, so for now I am just going
Mike McCormack6e2bca32004-07-04 00:25:00 +00001123 * to do all the directories for all the components.
Aric Stewart401bd3f2004-06-28 20:34:35 +00001124 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001125static UINT ACTION_CreateFolders(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00001126{
Aric Stewart8e233e92005-03-01 11:45:19 +00001127 static const WCHAR ExecSeqQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001128 {'S','E','L','E','C','T',' ',
1129 '`','D','i','r','e','c','t','o','r','y','_','`',
Aric Stewart8e233e92005-03-01 11:45:19 +00001130 ' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001131 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00001132 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001133 MSIQUERY *view;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001134
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001135 /* create all the empty folders specified in the CreateFolder table */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001136 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
Aric Stewart401bd3f2004-06-28 20:34:35 +00001137 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00001138 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001139
Aric Stewart2274ff12005-06-21 20:03:46 +00001140 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001141 msiobj_release(&view->hdr);
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001142
Mike McCormack9c845852005-10-29 11:29:17 +00001143 msi_create_component_directories( package );
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001144
Aric Stewart401bd3f2004-06-28 20:34:35 +00001145 return rc;
1146}
1147
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001148static UINT load_component( MSIRECORD *row, LPVOID param )
Aric Stewartbdb29552004-07-04 00:32:48 +00001149{
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001150 MSIPACKAGE *package = param;
Mike McCormack38d67a42005-08-22 09:15:23 +00001151 MSICOMPONENT *comp;
Aric Stewartbdb29552004-07-04 00:32:48 +00001152
Mike McCormackee034ba2005-09-20 11:59:14 +00001153 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
Mike McCormack38d67a42005-08-22 09:15:23 +00001154 if (!comp)
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001155 return ERROR_FUNCTION_FAILED;
1156
1157 list_add_tail( &package->components, &comp->entry );
Mike McCormack38d67a42005-08-22 09:15:23 +00001158
Aric Stewartbdb29552004-07-04 00:32:48 +00001159 /* fill in the data */
Mike McCormack51c66182005-10-27 12:36:12 +00001160 comp->Component = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001161
Mike McCormackefcc1ec2005-09-12 12:07:15 +00001162 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
Aric Stewartbdb29552004-07-04 00:32:48 +00001163
Mike McCormack51c66182005-10-27 12:36:12 +00001164 comp->ComponentId = msi_dup_record_field( row, 2 );
1165 comp->Directory = msi_dup_record_field( row, 3 );
Mike McCormack38d67a42005-08-22 09:15:23 +00001166 comp->Attributes = MSI_RecordGetInteger(row,4);
Mike McCormack51c66182005-10-27 12:36:12 +00001167 comp->Condition = msi_dup_record_field( row, 5 );
1168 comp->KeyPath = msi_dup_record_field( row, 6 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001169
James Hawkinsd893cb72006-09-20 19:55:01 -07001170 comp->Installed = INSTALLSTATE_UNKNOWN;
Mike McCormack575cc672006-10-26 14:09:29 +09001171 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
Aric Stewartfbdd7092004-12-27 19:06:22 +00001172
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001173 return ERROR_SUCCESS;
1174}
Aric Stewartbdb29552004-07-04 00:32:48 +00001175
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001176static UINT load_all_components( MSIPACKAGE *package )
1177{
1178 static const WCHAR query[] = {
1179 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1180 '`','C','o','m','p','o','n','e','n','t','`',0 };
1181 MSIQUERY *view;
1182 UINT r;
1183
1184 if (!list_empty(&package->components))
1185 return ERROR_SUCCESS;
1186
1187 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1188 if (r != ERROR_SUCCESS)
1189 return r;
1190
1191 r = MSI_IterateRecords(view, NULL, load_component, package);
1192 msiobj_release(&view->hdr);
1193 return r;
Aric Stewartbdb29552004-07-04 00:32:48 +00001194}
1195
Aric Stewart04598242005-06-23 16:43:24 +00001196typedef struct {
1197 MSIPACKAGE *package;
Mike McCormack1da28582005-08-22 14:09:17 +00001198 MSIFEATURE *feature;
Aric Stewart04598242005-06-23 16:43:24 +00001199} _ilfs;
1200
Mike McCormack38d67a42005-08-22 09:15:23 +00001201static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001202{
1203 ComponentList *cl;
1204
Mike McCormackee034ba2005-09-20 11:59:14 +00001205 cl = msi_alloc( sizeof (*cl) );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001206 if ( !cl )
1207 return ERROR_NOT_ENOUGH_MEMORY;
Mike McCormack38d67a42005-08-22 09:15:23 +00001208 cl->component = comp;
Mike McCormack1da28582005-08-22 14:09:17 +00001209 list_add_tail( &feature->Components, &cl->entry );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001210
1211 return ERROR_SUCCESS;
1212}
1213
James Hawkins545d0e72006-09-20 19:59:19 -07001214static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1215{
1216 FeatureList *fl;
1217
1218 fl = msi_alloc( sizeof(*fl) );
1219 if ( !fl )
1220 return ERROR_NOT_ENOUGH_MEMORY;
1221 fl->feature = child;
1222 list_add_tail( &parent->Children, &fl->entry );
1223
1224 return ERROR_SUCCESS;
1225}
1226
Aric Stewart04598242005-06-23 16:43:24 +00001227static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1228{
1229 _ilfs* ilfs= (_ilfs*)param;
1230 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00001231 MSICOMPONENT *comp;
Aric Stewart04598242005-06-23 16:43:24 +00001232
1233 component = MSI_RecordGetString(row,1);
1234
1235 /* check to see if the component is already loaded */
Mike McCormack38d67a42005-08-22 09:15:23 +00001236 comp = get_loaded_component( ilfs->package, component );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001237 if (!comp)
Aric Stewart04598242005-06-23 16:43:24 +00001238 {
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001239 ERR("unknown component %s\n", debugstr_w(component));
1240 return ERROR_FUNCTION_FAILED;
Aric Stewart04598242005-06-23 16:43:24 +00001241 }
1242
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001243 add_feature_component( ilfs->feature, comp );
1244 comp->Enabled = TRUE;
Aric Stewart04598242005-06-23 16:43:24 +00001245
1246 return ERROR_SUCCESS;
1247}
1248
James Hawkins545d0e72006-09-20 19:59:19 -07001249static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1250{
1251 MSIFEATURE *feature;
1252
James Hawkinsbfe07d12008-04-30 04:22:46 -05001253 if ( !name )
1254 return NULL;
1255
James Hawkins545d0e72006-09-20 19:59:19 -07001256 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1257 {
1258 if ( !lstrcmpW( feature->Feature, name ) )
1259 return feature;
1260 }
1261
1262 return NULL;
1263}
1264
Aric Stewart04598242005-06-23 16:43:24 +00001265static UINT load_feature(MSIRECORD * row, LPVOID param)
1266{
1267 MSIPACKAGE* package = (MSIPACKAGE*)param;
Mike McCormack1da28582005-08-22 14:09:17 +00001268 MSIFEATURE* feature;
Aric Stewart8e233e92005-03-01 11:45:19 +00001269 static const WCHAR Query1[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001270 {'S','E','L','E','C','T',' ',
1271 '`','C','o','m','p','o','n','e','n','t','_','`',
1272 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1273 'C','o','m','p','o','n','e','n','t','s','`',' ',
1274 'W','H','E','R','E',' ',
1275 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001276 MSIQUERY * view;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001277 UINT rc;
Aric Stewart04598242005-06-23 16:43:24 +00001278 _ilfs ilfs;
1279
Aric Stewartbdb29552004-07-04 00:32:48 +00001280 /* fill in the data */
1281
Mike McCormackee034ba2005-09-20 11:59:14 +00001282 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
Mike McCormack1da28582005-08-22 14:09:17 +00001283 if (!feature)
1284 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartbdb29552004-07-04 00:32:48 +00001285
James Hawkins545d0e72006-09-20 19:59:19 -07001286 list_init( &feature->Children );
Mike McCormack1da28582005-08-22 14:09:17 +00001287 list_init( &feature->Components );
Aric Stewartbdb29552004-07-04 00:32:48 +00001288
Mike McCormack51c66182005-10-27 12:36:12 +00001289 feature->Feature = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001290
Mike McCormack1da28582005-08-22 14:09:17 +00001291 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
Aric Stewartbdb29552004-07-04 00:32:48 +00001292
Mike McCormack51c66182005-10-27 12:36:12 +00001293 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1294 feature->Title = msi_dup_record_field( row, 3 );
1295 feature->Description = msi_dup_record_field( row, 4 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001296
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001297 if (!MSI_RecordIsNull(row,5))
Mike McCormack1da28582005-08-22 14:09:17 +00001298 feature->Display = MSI_RecordGetInteger(row,5);
Aric Stewartbdb29552004-07-04 00:32:48 +00001299
Mike McCormack1da28582005-08-22 14:09:17 +00001300 feature->Level= MSI_RecordGetInteger(row,6);
Mike McCormack51c66182005-10-27 12:36:12 +00001301 feature->Directory = msi_dup_record_field( row, 7 );
Mike McCormack1da28582005-08-22 14:09:17 +00001302 feature->Attributes = MSI_RecordGetInteger(row,8);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001303
James Hawkinsca5c1102006-09-20 19:53:56 -07001304 feature->Installed = INSTALLSTATE_UNKNOWN;
Mike McCormack575cc672006-10-26 14:09:29 +09001305 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
Mike McCormack1da28582005-08-22 14:09:17 +00001306
1307 list_add_tail( &package->features, &feature->entry );
Aric Stewartbdb29552004-07-04 00:32:48 +00001308
1309 /* load feature components */
1310
Mike McCormack1da28582005-08-22 14:09:17 +00001311 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001312 if (rc != ERROR_SUCCESS)
Aric Stewart04598242005-06-23 16:43:24 +00001313 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001314
Mike McCormack1da28582005-08-22 14:09:17 +00001315 ilfs.package = package;
1316 ilfs.feature = feature;
1317
Aric Stewart04598242005-06-23 16:43:24 +00001318 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001319 msiobj_release(&view->hdr);
Aric Stewart04598242005-06-23 16:43:24 +00001320
1321 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001322}
1323
James Hawkins545d0e72006-09-20 19:59:19 -07001324static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1325{
1326 MSIPACKAGE* package = (MSIPACKAGE*)param;
1327 MSIFEATURE *parent, *child;
1328
1329 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1330 if (!child)
1331 return ERROR_FUNCTION_FAILED;
1332
1333 if (!child->Feature_Parent)
1334 return ERROR_SUCCESS;
1335
1336 parent = find_feature_by_name( package, child->Feature_Parent );
1337 if (!parent)
1338 return ERROR_FUNCTION_FAILED;
1339
1340 add_feature_child( parent, child );
1341 return ERROR_SUCCESS;
1342}
1343
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001344static UINT load_all_features( MSIPACKAGE *package )
1345{
1346 static const WCHAR query[] = {
1347 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1348 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1349 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1350 MSIQUERY *view;
1351 UINT r;
1352
1353 if (!list_empty(&package->features))
1354 return ERROR_SUCCESS;
1355
1356 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1357 if (r != ERROR_SUCCESS)
1358 return r;
1359
1360 r = MSI_IterateRecords( view, NULL, load_feature, package );
James Hawkins545d0e72006-09-20 19:59:19 -07001361 if (r != ERROR_SUCCESS)
1362 return r;
1363
1364 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001365 msiobj_release( &view->hdr );
James Hawkins545d0e72006-09-20 19:59:19 -07001366
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001367 return r;
1368}
1369
Mike McCormackc1513be2006-03-21 19:40:36 +09001370static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1371{
1372 if (!p)
1373 return p;
1374 p = strchrW(p, ch);
1375 if (!p)
1376 return p;
1377 *p = 0;
1378 return p+1;
1379}
1380
James Hawkins41607222007-11-25 18:01:19 -06001381static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1382{
1383 static const WCHAR query[] = {
1384 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1385 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1386 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1387 MSIQUERY *view = NULL;
James Hawkins1277e1b2007-12-14 15:18:05 -06001388 MSIRECORD *row = NULL;
James Hawkins41607222007-11-25 18:01:19 -06001389 UINT r;
1390
1391 TRACE("%s\n", debugstr_w(file->File));
1392
1393 r = MSI_OpenQuery(package->db, &view, query, file->File);
1394 if (r != ERROR_SUCCESS)
1395 goto done;
1396
1397 r = MSI_ViewExecute(view, NULL);
1398 if (r != ERROR_SUCCESS)
1399 goto done;
1400
1401 r = MSI_ViewFetch(view, &row);
1402 if (r != ERROR_SUCCESS)
1403 goto done;
1404
1405 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1406 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1407 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1408 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1409 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1410
1411done:
1412 if (view) msiobj_release(&view->hdr);
James Hawkins1277e1b2007-12-14 15:18:05 -06001413 if (row) msiobj_release(&row->hdr);
James Hawkins41607222007-11-25 18:01:19 -06001414 return r;
1415}
1416
Aric Stewart04598242005-06-23 16:43:24 +00001417static UINT load_file(MSIRECORD *row, LPVOID param)
Aric Stewartc5a14432005-05-18 17:46:12 +00001418{
Aric Stewart04598242005-06-23 16:43:24 +00001419 MSIPACKAGE* package = (MSIPACKAGE*)param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00001420 LPCWSTR component;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001421 MSIFILE *file;
Aric Stewartc5a14432005-05-18 17:46:12 +00001422
1423 /* fill in the data */
1424
Mike McCormackee034ba2005-09-20 11:59:14 +00001425 file = msi_alloc_zero( sizeof (MSIFILE) );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001426 if (!file)
1427 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartc5a14432005-05-18 17:46:12 +00001428
Mike McCormack51c66182005-10-27 12:36:12 +00001429 file->File = msi_dup_record_field( row, 1 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001430
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001431 component = MSI_RecordGetString( row, 2 );
1432 file->Component = get_loaded_component( package, component );
Aric Stewart09b0aba2005-06-09 20:30:59 +00001433
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001434 if (!file->Component)
Aric Stewart09b0aba2005-06-09 20:30:59 +00001435 ERR("Unfound Component %s\n",debugstr_w(component));
Aric Stewartc5a14432005-05-18 17:46:12 +00001436
Mike McCormack51c66182005-10-27 12:36:12 +00001437 file->FileName = msi_dup_record_field( row, 3 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001438 reduce_to_longfilename( file->FileName );
Aric Stewartc5a14432005-05-18 17:46:12 +00001439
Mike McCormack51c66182005-10-27 12:36:12 +00001440 file->ShortName = msi_dup_record_field( row, 3 );
Mike McCormackc1513be2006-03-21 19:40:36 +09001441 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
Aric Stewartc5a14432005-05-18 17:46:12 +00001442
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001443 file->FileSize = MSI_RecordGetInteger( row, 4 );
Mike McCormack51c66182005-10-27 12:36:12 +00001444 file->Version = msi_dup_record_field( row, 5 );
1445 file->Language = msi_dup_record_field( row, 6 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001446 file->Attributes = MSI_RecordGetInteger( row, 7 );
1447 file->Sequence = MSI_RecordGetInteger( row, 8 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001448
Mike McCormackdded8fb2005-11-02 10:56:42 +00001449 file->state = msifs_invalid;
Aric Stewartc5a14432005-05-18 17:46:12 +00001450
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001451 /* if the compressed bits are not set in the file attributes,
1452 * then read the information from the package word count property
1453 */
James Hawkins98d14862006-07-31 11:15:52 -07001454 if (file->Attributes & msidbFileAttributesCompressed)
1455 {
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001456 file->IsCompressed = TRUE;
1457 }
1458 else if (file->Attributes & msidbFileAttributesNoncompressed)
1459 {
1460 file->IsCompressed = FALSE;
1461 }
1462 else
1463 {
1464 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1465 }
1466
James Hawkins41607222007-11-25 18:01:19 -06001467 load_file_hash(package, file);
1468
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001469 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1470
1471 list_add_tail( &package->files, &file->entry );
Aric Stewartc5a14432005-05-18 17:46:12 +00001472
1473 return ERROR_SUCCESS;
1474}
1475
1476static UINT load_all_files(MSIPACKAGE *package)
1477{
1478 MSIQUERY * view;
Aric Stewartc5a14432005-05-18 17:46:12 +00001479 UINT rc;
1480 static const WCHAR Query[] =
1481 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001482 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1483 '`','S','e','q','u','e','n','c','e','`', 0};
Aric Stewartc5a14432005-05-18 17:46:12 +00001484
Mike McCormack9a9195d2006-07-19 17:01:07 +09001485 if (!list_empty(&package->files))
1486 return ERROR_SUCCESS;
1487
Aric Stewartc5a14432005-05-18 17:46:12 +00001488 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1489 if (rc != ERROR_SUCCESS)
1490 return ERROR_SUCCESS;
Aric Stewartc5a14432005-05-18 17:46:12 +00001491
Aric Stewart04598242005-06-23 16:43:24 +00001492 rc = MSI_IterateRecords(view, NULL, load_file, package);
Aric Stewartc5a14432005-05-18 17:46:12 +00001493 msiobj_release(&view->hdr);
1494
1495 return ERROR_SUCCESS;
1496}
1497
Mike McCormack7eb27022006-11-22 15:13:12 +09001498static UINT load_folder( MSIRECORD *row, LPVOID param )
1499{
1500 MSIPACKAGE *package = param;
1501 static const WCHAR szDot[] = { '.',0 };
1502 static WCHAR szEmpty[] = { 0 };
1503 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1504 MSIFOLDER *folder;
1505
1506 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1507 if (!folder)
1508 return ERROR_NOT_ENOUGH_MEMORY;
1509
1510 folder->Directory = msi_dup_record_field( row, 1 );
1511
1512 TRACE("%s\n", debugstr_w(folder->Directory));
1513
1514 p = msi_dup_record_field(row, 3);
1515
1516 /* split src and target dir */
1517 tgt_short = p;
1518 src_short = folder_split_path( p, ':' );
1519
1520 /* split the long and short paths */
1521 tgt_long = folder_split_path( tgt_short, '|' );
1522 src_long = folder_split_path( src_short, '|' );
1523
1524 /* check for no-op dirs */
1525 if (!lstrcmpW(szDot, tgt_short))
1526 tgt_short = szEmpty;
1527 if (!lstrcmpW(szDot, src_short))
1528 src_short = szEmpty;
1529
1530 if (!tgt_long)
1531 tgt_long = tgt_short;
1532
1533 if (!src_short) {
1534 src_short = tgt_short;
1535 src_long = tgt_long;
1536 }
1537
1538 if (!src_long)
1539 src_long = src_short;
1540
1541 /* FIXME: use the target short path too */
1542 folder->TargetDefault = strdupW(tgt_long);
1543 folder->SourceShortPath = strdupW(src_short);
1544 folder->SourceLongPath = strdupW(src_long);
1545 msi_free(p);
1546
1547 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1548 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1549 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1550
1551 folder->Parent = msi_dup_record_field( row, 2 );
1552
1553 folder->Property = msi_dup_property( package, folder->Directory );
1554
1555 list_add_tail( &package->folders, &folder->entry );
1556
1557 TRACE("returning %p\n", folder);
1558
1559 return ERROR_SUCCESS;
1560}
1561
1562static UINT load_all_folders( MSIPACKAGE *package )
1563{
1564 static const WCHAR query[] = {
1565 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1566 '`','D','i','r','e','c','t','o','r','y','`',0 };
1567 MSIQUERY *view;
1568 UINT r;
1569
1570 if (!list_empty(&package->folders))
1571 return ERROR_SUCCESS;
1572
1573 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1574 if (r != ERROR_SUCCESS)
1575 return r;
1576
1577 r = MSI_IterateRecords(view, NULL, load_folder, package);
1578 msiobj_release(&view->hdr);
1579 return r;
1580}
Aric Stewartc5a14432005-05-18 17:46:12 +00001581
Aric Stewartbdb29552004-07-04 00:32:48 +00001582/*
Mike McCormack9a9195d2006-07-19 17:01:07 +09001583 * I am not doing any of the costing functionality yet.
Aric Stewartbdb29552004-07-04 00:32:48 +00001584 * Mostly looking at doing the Component and Feature loading
1585 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001586 * The native MSI does A LOT of modification to tables here. Mostly adding
Mike McCormack9a9195d2006-07-19 17:01:07 +09001587 * a lot of temporary columns to the Feature and Component tables.
Aric Stewartbdb29552004-07-04 00:32:48 +00001588 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001589 * note: Native msi also tracks the short filename. But I am only going to
Aric Stewartbdb29552004-07-04 00:32:48 +00001590 * track the long ones. Also looking at this directory table
1591 * it appears that the directory table does not get the parents
Mike McCormack9a9195d2006-07-19 17:01:07 +09001592 * resolved base on property only based on their entries in the
Aric Stewartbdb29552004-07-04 00:32:48 +00001593 * directory table.
1594 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001595static UINT ACTION_CostInitialize(MSIPACKAGE *package)
Aric Stewartbdb29552004-07-04 00:32:48 +00001596{
Aric Stewart8e233e92005-03-01 11:45:19 +00001597 static const WCHAR szCosting[] =
1598 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001599 static const WCHAR szZero[] = { '0', 0 };
Aric Stewartbdb29552004-07-04 00:32:48 +00001600
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001601 MSI_SetPropertyW(package, szCosting, szZero);
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001602 MSI_SetPropertyW(package, cszRootDrive, c_colon);
Aric Stewartbdb29552004-07-04 00:32:48 +00001603
James Hawkinsdbbd5ca2008-06-10 17:33:29 -05001604 load_all_folders( package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001605 load_all_components( package );
1606 load_all_features( package );
1607 load_all_files( package );
Aric Stewartec688fb2004-07-04 00:35:52 +00001608
Aric Stewartec688fb2004-07-04 00:35:52 +00001609 return ERROR_SUCCESS;
1610}
1611
Mike McCormackf9acfe62005-06-07 20:29:51 +00001612static UINT execute_script(MSIPACKAGE *package, UINT script )
Aric Stewart9cd707d2005-05-27 19:24:22 +00001613{
James Hawkinsbb54ed12007-11-05 04:36:49 -05001614 UINT i;
Aric Stewart9cd707d2005-05-27 19:24:22 +00001615 UINT rc = ERROR_SUCCESS;
1616
1617 TRACE("Executing Script %i\n",script);
1618
Mike McCormackaa81e4f2006-01-10 12:09:19 +01001619 if (!package->script)
1620 {
1621 ERR("no script!\n");
1622 return ERROR_FUNCTION_FAILED;
1623 }
1624
Aric Stewart9cd707d2005-05-27 19:24:22 +00001625 for (i = 0; i < package->script->ActionCount[script]; i++)
1626 {
1627 LPWSTR action;
1628 action = package->script->Actions[script][i];
1629 ui_actionstart(package, action);
1630 TRACE("Executing Action (%s)\n",debugstr_w(action));
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001631 rc = ACTION_PerformAction(package, action, script, TRUE);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001632 if (rc != ERROR_SUCCESS)
1633 break;
1634 }
Mike McCormackf86cfd42006-11-02 18:12:43 +09001635 msi_free_action_script(package, script);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001636 return rc;
1637}
1638
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001639static UINT ACTION_FileCost(MSIPACKAGE *package)
Aric Stewartec688fb2004-07-04 00:35:52 +00001640{
Aric Stewartbdb29552004-07-04 00:32:48 +00001641 return ERROR_SUCCESS;
1642}
1643
Mike McCormackb7669152006-10-30 16:35:09 +09001644static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001645{
Mike McCormack38d67a42005-08-22 09:15:23 +00001646 MSICOMPONENT *comp;
Aric Stewart78a04e32005-02-22 15:47:00 +00001647
Mike McCormack38d67a42005-08-22 09:15:23 +00001648 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001649 {
1650 INSTALLSTATE res;
James Hawkins32f57022006-09-20 19:57:03 -07001651
1652 if (!comp->ComponentId)
1653 continue;
1654
Mike McCormackb7669152006-10-30 16:35:09 +09001655 res = MsiGetComponentPathW( package->ProductCode,
Mike McCormack38d67a42005-08-22 09:15:23 +00001656 comp->ComponentId, NULL, NULL);
Aric Stewart78a04e32005-02-22 15:47:00 +00001657 if (res < 0)
1658 res = INSTALLSTATE_ABSENT;
Mike McCormack38d67a42005-08-22 09:15:23 +00001659 comp->Installed = res;
Aric Stewart78a04e32005-02-22 15:47:00 +00001660 }
Mike McCormackb7669152006-10-30 16:35:09 +09001661}
1662
1663/* scan for and update current install states */
1664static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1665{
1666 MSICOMPONENT *comp;
1667 MSIFEATURE *feature;
Aric Stewart78a04e32005-02-22 15:47:00 +00001668
Mike McCormack1da28582005-08-22 14:09:17 +00001669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001670 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001671 ComponentList *cl;
James Hawkins545d0e72006-09-20 19:59:19 -07001672 INSTALLSTATE res = INSTALLSTATE_ABSENT;
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001673
Mike McCormack1da28582005-08-22 14:09:17 +00001674 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001675 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001676 comp= cl->component;
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001677
James Hawkins32f57022006-09-20 19:57:03 -07001678 if (!comp->ComponentId)
1679 {
1680 res = INSTALLSTATE_ABSENT;
1681 break;
1682 }
1683
James Hawkins545d0e72006-09-20 19:59:19 -07001684 if (res == INSTALLSTATE_ABSENT)
Mike McCormack38d67a42005-08-22 09:15:23 +00001685 res = comp->Installed;
Aric Stewart78a04e32005-02-22 15:47:00 +00001686 else
1687 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001688 if (res == comp->Installed)
Aric Stewart78a04e32005-02-22 15:47:00 +00001689 continue;
1690
Paul Vriensded99432006-11-12 12:01:26 +01001691 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
James Hawkins32f57022006-09-20 19:57:03 -07001692 res != INSTALLSTATE_SOURCE)
1693 {
1694 res = INSTALLSTATE_INCOMPLETE;
1695 }
Aric Stewart78a04e32005-02-22 15:47:00 +00001696 }
1697 }
Mike McCormack8aa1a912005-08-25 19:19:10 +00001698 feature->Installed = res;
Aric Stewart78a04e32005-02-22 15:47:00 +00001699 }
1700}
1701
Aric Stewart78a04e32005-02-22 15:47:00 +00001702static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1703 INSTALLSTATE state)
Aric Stewartae1aa322004-12-27 19:02:59 +00001704{
Aric Stewartae1aa322004-12-27 19:02:59 +00001705 static const WCHAR all[]={'A','L','L',0};
Mike McCormack72faac02005-09-08 11:03:35 +00001706 LPWSTR override;
Mike McCormack1da28582005-08-22 14:09:17 +00001707 MSIFEATURE *feature;
Aric Stewartae1aa322004-12-27 19:02:59 +00001708
Mike McCormack062ad502005-09-15 15:04:08 +00001709 override = msi_dup_property( package, property );
Mike McCormack72faac02005-09-08 11:03:35 +00001710 if (!override)
1711 return FALSE;
Mike McCormack575cc672006-10-26 14:09:29 +09001712
Mike McCormack72faac02005-09-08 11:03:35 +00001713 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001714 {
Mike McCormack72faac02005-09-08 11:03:35 +00001715 if (strcmpiW(override,all)==0)
Mike McCormack575cc672006-10-26 14:09:29 +09001716 msi_feature_set_state( feature, state );
Mike McCormack72faac02005-09-08 11:03:35 +00001717 else
1718 {
1719 LPWSTR ptr = override;
1720 LPWSTR ptr2 = strchrW(override,',');
Aric Stewartd900b532004-12-27 19:12:35 +00001721
Mike McCormack72faac02005-09-08 11:03:35 +00001722 while (ptr)
1723 {
1724 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1725 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
Aric Stewartd900b532004-12-27 19:12:35 +00001726 {
Mike McCormack575cc672006-10-26 14:09:29 +09001727 msi_feature_set_state( feature, state );
Mike McCormack72faac02005-09-08 11:03:35 +00001728 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001729 }
Mike McCormack72faac02005-09-08 11:03:35 +00001730 if (ptr2)
1731 {
1732 ptr=ptr2+1;
1733 ptr2 = strchrW(ptr,',');
1734 }
1735 else
1736 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001737 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001738 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001739 }
Mike McCormackee034ba2005-09-20 11:59:14 +00001740 msi_free(override);
Aric Stewart78a04e32005-02-22 15:47:00 +00001741
Mike McCormack72faac02005-09-08 11:03:35 +00001742 return TRUE;
Aric Stewart78a04e32005-02-22 15:47:00 +00001743}
1744
James Hawkins7bcac312006-07-19 11:17:16 -07001745UINT MSI_SetFeatureStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001746{
Mike McCormack74f0de92005-09-29 10:32:39 +00001747 int install_level;
Aric Stewart8e233e92005-03-01 11:45:19 +00001748 static const WCHAR szlevel[] =
1749 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1750 static const WCHAR szAddLocal[] =
1751 {'A','D','D','L','O','C','A','L',0};
James Hawkinsc31fd432007-11-06 05:22:11 -06001752 static const WCHAR szAddSource[] =
1753 {'A','D','D','S','O','U','R','C','E',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00001754 static const WCHAR szRemove[] =
1755 {'R','E','M','O','V','E',0};
Aric Stewartd5655f92005-11-02 14:21:17 +00001756 static const WCHAR szReinstall[] =
1757 {'R','E','I','N','S','T','A','L','L',0};
Aric Stewart78a04e32005-02-22 15:47:00 +00001758 BOOL override = FALSE;
Mike McCormack38d67a42005-08-22 09:15:23 +00001759 MSICOMPONENT* component;
Mike McCormack1da28582005-08-22 14:09:17 +00001760 MSIFEATURE *feature;
1761
Aric Stewart78a04e32005-02-22 15:47:00 +00001762
1763 /* I do not know if this is where it should happen.. but */
1764
1765 TRACE("Checking Install Level\n");
1766
Mike McCormack74f0de92005-09-29 10:32:39 +00001767 install_level = msi_get_property_int( package, szlevel, 1 );
Aric Stewart78a04e32005-02-22 15:47:00 +00001768
Francois Gouget58162f82006-10-13 02:19:42 +02001769 /* ok here is the _real_ rub
Francois Gougetfbb33432005-03-02 13:53:50 +00001770 * all these activation/deactivation things happen in order and things
1771 * later on the list override things earlier on the list.
Aric Stewart78a04e32005-02-22 15:47:00 +00001772 * 1) INSTALLLEVEL processing
1773 * 2) ADDLOCAL
1774 * 3) REMOVE
1775 * 4) ADDSOURCE
1776 * 5) ADDDEFAULT
1777 * 6) REINSTALL
1778 * 7) COMPADDLOCAL
1779 * 8) COMPADDSOURCE
1780 * 9) FILEADDLOCAL
1781 * 10) FILEADDSOURCE
1782 * 11) FILEADDDEFAULT
Aric Stewart78a04e32005-02-22 15:47:00 +00001783 *
Francois Gougetfbb33432005-03-02 13:53:50 +00001784 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1785 * REMOVE are the big ones, since we don't handle administrative installs
1786 * yet anyway.
Aric Stewart78a04e32005-02-22 15:47:00 +00001787 */
1788 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1789 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
James Hawkinsc31fd432007-11-06 05:22:11 -06001790 override |= process_state_property(package,szAddSource,INSTALLSTATE_SOURCE);
Aric Stewartd5655f92005-11-02 14:21:17 +00001791 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
Aric Stewart78a04e32005-02-22 15:47:00 +00001792
1793 if (!override)
Aric Stewartfbdd7092004-12-27 19:06:22 +00001794 {
Mike McCormack1da28582005-08-22 14:09:17 +00001795 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001796 {
Mike McCormack1da28582005-08-22 14:09:17 +00001797 BOOL feature_state = ((feature->Level > 0) &&
1798 (feature->Level <= install_level));
Aric Stewartae1aa322004-12-27 19:02:59 +00001799
Mike McCormack1da28582005-08-22 14:09:17 +00001800 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001801 {
Mike McCormack1da28582005-08-22 14:09:17 +00001802 if (feature->Attributes & msidbFeatureAttributesFavorSource)
Mike McCormack6395ff62006-10-26 12:34:52 +09001803 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
Mike McCormack1da28582005-08-22 14:09:17 +00001804 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
Mike McCormack6395ff62006-10-26 12:34:52 +09001805 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
Aric Stewartb39d8fc2005-05-13 13:56:39 +00001806 else
Mike McCormack6395ff62006-10-26 12:34:52 +09001807 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
Aric Stewartfbdd7092004-12-27 19:06:22 +00001808 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001809 }
James Hawkins545d0e72006-09-20 19:59:19 -07001810
1811 /* disable child features of unselected parent features */
1812 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1813 {
1814 FeatureList *fl;
1815
1816 if (feature->Level > 0 && feature->Level <= install_level)
1817 continue;
1818
1819 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
Mike McCormack6395ff62006-10-26 12:34:52 +09001820 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
James Hawkins545d0e72006-09-20 19:59:19 -07001821 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001822 }
Aric Stewart6999a042005-06-08 19:20:02 +00001823 else
1824 {
1825 /* set the Preselected Property */
1826 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1827 static const WCHAR szOne[] = { '1', 0 };
1828
1829 MSI_SetPropertyW(package,szPreselected,szOne);
1830 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001831
Aric Stewartfbdd7092004-12-27 19:06:22 +00001832 /*
Mike McCormack6395ff62006-10-26 12:34:52 +09001833 * now we want to enable or disable components base on feature
1834 */
Aric Stewartfbdd7092004-12-27 19:06:22 +00001835
Mike McCormack1da28582005-08-22 14:09:17 +00001836 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001837 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001838 ComponentList *cl;
1839
James Hawkins62219752008-05-19 02:27:50 -05001840 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1841 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1842
1843 if (!feature->Level)
1844 continue;
Mike McCormack97419ae2006-12-05 18:24:39 +09001845
1846 /* features with components that have compressed files are made local */
1847 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1848 {
1849 if (cl->component->Enabled &&
1850 cl->component->ForceLocalState &&
1851 feature->Action == INSTALLSTATE_SOURCE)
1852 {
1853 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1854 break;
1855 }
1856 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001857
Mike McCormack1da28582005-08-22 14:09:17 +00001858 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001859 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001860 component = cl->component;
Aric Stewartfbdd7092004-12-27 19:06:22 +00001861
Mike McCormack87fa8542006-11-10 15:38:51 +09001862 if (!component->Enabled)
1863 continue;
1864
Mike McCormack97419ae2006-12-05 18:24:39 +09001865 switch (feature->Action)
Mike McCormackad80ece2006-11-10 15:38:31 +09001866 {
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001867 case INSTALLSTATE_ABSENT:
1868 component->anyAbsent = 1;
1869 break;
Mike McCormack97419ae2006-12-05 18:24:39 +09001870 case INSTALLSTATE_ADVERTISED:
1871 component->hasAdvertiseFeature = 1;
1872 break;
1873 case INSTALLSTATE_SOURCE:
1874 component->hasSourceFeature = 1;
1875 break;
1876 case INSTALLSTATE_LOCAL:
1877 component->hasLocalFeature = 1;
1878 break;
1879 case INSTALLSTATE_DEFAULT:
1880 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1881 component->hasAdvertiseFeature = 1;
1882 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1883 component->hasSourceFeature = 1;
Mike McCormackad80ece2006-11-10 15:38:31 +09001884 else
Mike McCormack97419ae2006-12-05 18:24:39 +09001885 component->hasLocalFeature = 1;
1886 break;
1887 default:
1888 break;
James Hawkins929395c2006-10-19 15:51:33 -07001889 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001890 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001891 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001892
Mike McCormack38d67a42005-08-22 09:15:23 +00001893 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001894 {
Mike McCormack97419ae2006-12-05 18:24:39 +09001895 /* if the component isn't enabled, leave it alone */
1896 if (!component->Enabled)
1897 continue;
1898
1899 /* check if it's local or source */
1900 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1901 (component->hasLocalFeature || component->hasSourceFeature))
1902 {
1903 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1904 !component->ForceLocalState)
1905 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1906 else
1907 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1908 continue;
1909 }
1910
1911 /* if any feature is local, the component must be local too */
1912 if (component->hasLocalFeature)
1913 {
1914 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1915 continue;
1916 }
1917
1918 if (component->hasSourceFeature)
1919 {
1920 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1921 continue;
1922 }
1923
1924 if (component->hasAdvertiseFeature)
1925 {
1926 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1927 continue;
1928 }
1929
1930 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001931 if (component->anyAbsent)
1932 msi_component_set_state(component, INSTALLSTATE_ABSENT);
Mike McCormack97419ae2006-12-05 18:24:39 +09001933 }
1934
1935 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1936 {
Mike McCormack9efb7b72006-11-07 17:55:43 +09001937 if (component->Action == INSTALLSTATE_DEFAULT)
1938 {
1939 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1940 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1941 }
1942
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001943 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1944 debugstr_w(component->Component), component->Installed, component->Action);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001945 }
1946
1947
Aric Stewartae1aa322004-12-27 19:02:59 +00001948 return ERROR_SUCCESS;
1949}
1950
Aric Stewart443ad4d2005-06-21 20:50:12 +00001951static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1952{
1953 MSIPACKAGE *package = (MSIPACKAGE*)param;
1954 LPCWSTR name;
1955 LPWSTR path;
James Hawkinsbaad8882007-05-01 03:19:50 -05001956 MSIFOLDER *f;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001957
1958 name = MSI_RecordGetString(row,1);
1959
James Hawkinsbaad8882007-05-01 03:19:50 -05001960 f = get_loaded_folder(package, name);
1961 if (!f) return ERROR_SUCCESS;
1962
1963 /* reset the ResolvedTarget */
1964 msi_free(f->ResolvedTarget);
1965 f->ResolvedTarget = NULL;
1966
Aric Stewart443ad4d2005-06-21 20:50:12 +00001967 /* This helper function now does ALL the work */
1968 TRACE("Dir %s ...\n",debugstr_w(name));
James Hawkins8cedb212007-03-29 02:38:57 -05001969 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001970 TRACE("resolves to %s\n",debugstr_w(path));
Mike McCormackee034ba2005-09-20 11:59:14 +00001971 msi_free(path);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001972
1973 return ERROR_SUCCESS;
1974}
1975
1976static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1977{
1978 MSIPACKAGE *package = (MSIPACKAGE*)param;
Mike McCormack1da28582005-08-22 14:09:17 +00001979 LPCWSTR name;
1980 MSIFEATURE *feature;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001981
Mike McCormack1da28582005-08-22 14:09:17 +00001982 name = MSI_RecordGetString( row, 1 );
Aric Stewart443ad4d2005-06-21 20:50:12 +00001983
Mike McCormack1da28582005-08-22 14:09:17 +00001984 feature = get_loaded_feature( package, name );
1985 if (!feature)
1986 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
Aric Stewart443ad4d2005-06-21 20:50:12 +00001987 else
1988 {
1989 LPCWSTR Condition;
1990 Condition = MSI_RecordGetString(row,3);
1991
Aric Stewart0713f092005-06-24 11:51:29 +00001992 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
Aric Stewart443ad4d2005-06-21 20:50:12 +00001993 {
1994 int level = MSI_RecordGetInteger(row,2);
Francois Gouget633ee952008-05-06 20:01:59 +02001995 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
Mike McCormack1da28582005-08-22 14:09:17 +00001996 feature->Level = level;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001997 }
1998 }
1999 return ERROR_SUCCESS;
2000}
2001
Andrew Talbot020bda72007-01-12 16:47:57 +00002002static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
Mike McCormackd1723de2006-10-24 17:37:26 +09002003{
2004 static const WCHAR name_fmt[] =
2005 {'%','u','.','%','u','.','%','u','.','%','u',0};
Dmitry Timoshkov76d6b762008-05-26 13:06:47 +09002006 static const WCHAR name[] = {'\\',0};
Mike McCormackd1723de2006-10-24 17:37:26 +09002007 VS_FIXEDFILEINFO *lpVer;
2008 WCHAR filever[0x100];
2009 LPVOID version;
2010 DWORD versize;
2011 DWORD handle;
2012 UINT sz;
2013
2014 TRACE("%s\n", debugstr_w(filename));
2015
2016 versize = GetFileVersionInfoSizeW( filename, &handle );
2017 if (!versize)
2018 return NULL;
2019
2020 version = msi_alloc( versize );
2021 GetFileVersionInfoW( filename, 0, versize, version );
2022
Rob Shearman9c6fac62007-06-26 22:22:52 +01002023 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2024 {
2025 msi_free( version );
2026 return NULL;
2027 }
Mike McCormackd1723de2006-10-24 17:37:26 +09002028
2029 sprintfW( filever, name_fmt,
2030 HIWORD(lpVer->dwFileVersionMS),
2031 LOWORD(lpVer->dwFileVersionMS),
2032 HIWORD(lpVer->dwFileVersionLS),
2033 LOWORD(lpVer->dwFileVersionLS));
2034
Rob Shearman023383a2007-06-26 22:23:30 +01002035 msi_free( version );
2036
Mike McCormackd1723de2006-10-24 17:37:26 +09002037 return strdupW( filever );
2038}
2039
Mike McCormackc5c55212006-11-07 15:05:48 +09002040static UINT msi_check_file_install_states( MSIPACKAGE *package )
Aric Stewart401bd3f2004-06-28 20:34:35 +00002041{
Mike McCormackc5c55212006-11-07 15:05:48 +09002042 LPWSTR file_version;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002043 MSIFILE *file;
Aric Stewartec688fb2004-07-04 00:35:52 +00002044
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002045 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartec688fb2004-07-04 00:35:52 +00002046 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00002047 MSICOMPONENT* comp = file->Component;
2048 LPWSTR p;
Aric Stewartec688fb2004-07-04 00:35:52 +00002049
Mike McCormackf11c8b02005-09-09 14:48:51 +00002050 if (!comp)
2051 continue;
Aric Stewartec688fb2004-07-04 00:35:52 +00002052
James Hawkinsd893cb72006-09-20 19:55:01 -07002053 if (file->IsCompressed)
James Hawkinsd893cb72006-09-20 19:55:01 -07002054 comp->ForceLocalState = TRUE;
James Hawkinsd893cb72006-09-20 19:55:01 -07002055
Mike McCormackf11c8b02005-09-09 14:48:51 +00002056 /* calculate target */
James Hawkins8cedb212007-03-29 02:38:57 -05002057 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002058
Mike McCormackee034ba2005-09-20 11:59:14 +00002059 msi_free(file->TargetPath);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002060
2061 TRACE("file %s is named %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09002062 debugstr_w(file->File), debugstr_w(file->FileName));
Mike McCormackf11c8b02005-09-09 14:48:51 +00002063
2064 file->TargetPath = build_directory_name(2, p, file->FileName);
2065
Mike McCormackee034ba2005-09-20 11:59:14 +00002066 msi_free(p);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002067
2068 TRACE("file %s resolves to %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09002069 debugstr_w(file->File), debugstr_w(file->TargetPath));
Mike McCormackf11c8b02005-09-09 14:48:51 +00002070
Mike McCormackddf0b592006-10-31 14:32:48 +09002071 /* don't check files of components that aren't installed */
2072 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2073 comp->Installed == INSTALLSTATE_ABSENT)
2074 {
2075 file->state = msifs_missing; /* assume files are missing */
2076 continue;
2077 }
2078
Mike McCormackf11c8b02005-09-09 14:48:51 +00002079 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
Aric Stewartec688fb2004-07-04 00:35:52 +00002080 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002081 file->state = msifs_missing;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002082 comp->Cost += file->FileSize;
Mike McCormackddf0b592006-10-31 14:32:48 +09002083 comp->Installed = INSTALLSTATE_INCOMPLETE;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002084 continue;
2085 }
Mike McCormackba8200b2004-12-22 15:25:30 +00002086
Mike McCormackd1723de2006-10-24 17:37:26 +09002087 if (file->Version &&
2088 (file_version = msi_get_disk_file_version( file->TargetPath )))
Mike McCormackf11c8b02005-09-09 14:48:51 +00002089 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00002090 TRACE("new %s old %s\n", debugstr_w(file->Version),
Mike McCormackd1723de2006-10-24 17:37:26 +09002091 debugstr_w(file_version));
2092 /* FIXME: seems like a bad way to compare version numbers */
2093 if (lstrcmpiW(file_version, file->Version)<0)
Aric Stewartec688fb2004-07-04 00:35:52 +00002094 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002095 file->state = msifs_overwrite;
Aric Stewartec688fb2004-07-04 00:35:52 +00002096 comp->Cost += file->FileSize;
Mike McCormackddf0b592006-10-31 14:32:48 +09002097 comp->Installed = INSTALLSTATE_INCOMPLETE;
Aric Stewartec688fb2004-07-04 00:35:52 +00002098 }
2099 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002100 file->state = msifs_present;
Mike McCormackd1723de2006-10-24 17:37:26 +09002101 msi_free( file_version );
Mike McCormackf11c8b02005-09-09 14:48:51 +00002102 }
2103 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002104 file->state = msifs_present;
Aric Stewartec688fb2004-07-04 00:35:52 +00002105 }
2106
Mike McCormackc5c55212006-11-07 15:05:48 +09002107 return ERROR_SUCCESS;
2108}
2109
2110/*
2111 * A lot is done in this function aside from just the costing.
2112 * The costing needs to be implemented at some point but for now I am going
2113 * to focus on the directory building
2114 *
2115 */
2116static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2117{
2118 static const WCHAR ExecSeqQuery[] =
2119 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2120 '`','D','i','r','e','c','t','o','r','y','`',0};
2121 static const WCHAR ConditionQuery[] =
2122 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2123 '`','C','o','n','d','i','t','i','o','n','`',0};
2124 static const WCHAR szCosting[] =
2125 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2126 static const WCHAR szlevel[] =
2127 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
James Hawkinsece5a042008-05-13 20:31:44 -05002128 static const WCHAR szOutOfDiskSpace[] =
2129 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
Mike McCormackc5c55212006-11-07 15:05:48 +09002130 static const WCHAR szOne[] = { '1', 0 };
James Hawkinsece5a042008-05-13 20:31:44 -05002131 static const WCHAR szZero[] = { '0', 0 };
Mike McCormackc5c55212006-11-07 15:05:48 +09002132 MSICOMPONENT *comp;
2133 UINT rc;
2134 MSIQUERY * view;
2135 LPWSTR level;
2136
2137 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2138 return ERROR_SUCCESS;
2139
2140 TRACE("Building Directory properties\n");
2141
2142 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2143 if (rc == ERROR_SUCCESS)
2144 {
2145 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2146 package);
2147 msiobj_release(&view->hdr);
2148 }
2149
2150 /* read components states from the registry */
2151 ACTION_GetComponentInstallStates(package);
2152
2153 TRACE("File calculations\n");
2154 msi_check_file_install_states( package );
2155
Aric Stewart7d3e5972004-07-04 00:36:58 +00002156 TRACE("Evaluating Condition Table\n");
Aric Stewart2e9b5f72004-07-04 00:31:17 +00002157
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002158 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
Aric Stewart84837d92004-07-20 01:22:37 +00002159 if (rc == ERROR_SUCCESS)
2160 {
Aric Stewart443ad4d2005-06-21 20:50:12 +00002161 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2162 package);
Mike McCormackac6a4132005-01-04 20:36:12 +00002163 msiobj_release(&view->hdr);
Aric Stewart84837d92004-07-20 01:22:37 +00002164 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002165
2166 TRACE("Enabling or Disabling Components\n");
Mike McCormack38d67a42005-08-22 09:15:23 +00002167 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewart7d3e5972004-07-04 00:36:58 +00002168 {
Mike McCormack9375fd92006-10-27 17:29:02 +09002169 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002170 {
Mike McCormack9375fd92006-10-27 17:29:02 +09002171 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2172 comp->Enabled = FALSE;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002173 }
2174 }
2175
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002176 MSI_SetPropertyW(package,szCosting,szOne);
Aric Stewart8cc14a92004-12-27 18:56:30 +00002177 /* set default run level if not set */
Mike McCormack062ad502005-09-15 15:04:08 +00002178 level = msi_dup_property( package, szlevel );
Aric Stewart8cc14a92004-12-27 18:56:30 +00002179 if (!level)
2180 MSI_SetPropertyW(package,szlevel, szOne);
Mike McCormackee034ba2005-09-20 11:59:14 +00002181 msi_free(level);
Aric Stewartae1aa322004-12-27 19:02:59 +00002182
James Hawkinsece5a042008-05-13 20:31:44 -05002183 /* FIXME: check volume disk space */
2184 MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2185
Mike McCormackb7669152006-10-30 16:35:09 +09002186 ACTION_UpdateFeatureInstallStates(package);
Aric Stewartae1aa322004-12-27 19:02:59 +00002187
James Hawkins7c7f0bb2006-07-19 11:15:37 -07002188 return MSI_SetFeatureStates(package);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002189}
2190
Francois Gougetda8b3dd2005-01-26 21:09:04 +00002191/* OK this value is "interpreted" and then formatted based on the
Aric Stewart6e160f12004-06-29 04:07:22 +00002192 first few characters */
Aric Stewart09b0aba2005-06-09 20:30:59 +00002193static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
Aric Stewart401bd3f2004-06-28 20:34:35 +00002194 DWORD *size)
2195{
2196 LPSTR data = NULL;
James Hawkins2f658cb2008-02-04 19:06:53 -06002197
Aric Stewart6e160f12004-06-29 04:07:22 +00002198 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
Aric Stewart401bd3f2004-06-28 20:34:35 +00002199 {
Aric Stewart6e160f12004-06-29 04:07:22 +00002200 if (value[1]=='x')
2201 {
2202 LPWSTR ptr;
2203 CHAR byte[5];
Aric Stewart6186b2b2005-05-16 21:37:35 +00002204 LPWSTR deformated = NULL;
Aric Stewart6e160f12004-06-29 04:07:22 +00002205 int count;
2206
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002207 deformat_string(package, &value[2], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002208
2209 /* binary value type */
Aric Stewart6186b2b2005-05-16 21:37:35 +00002210 ptr = deformated;
2211 *type = REG_BINARY;
2212 if (strlenW(ptr)%2)
2213 *size = (strlenW(ptr)/2)+1;
2214 else
2215 *size = strlenW(ptr)/2;
2216
Mike McCormackee034ba2005-09-20 11:59:14 +00002217 data = msi_alloc(*size);
Aric Stewart6186b2b2005-05-16 21:37:35 +00002218
Aric Stewart6e160f12004-06-29 04:07:22 +00002219 byte[0] = '0';
2220 byte[1] = 'x';
2221 byte[4] = 0;
2222 count = 0;
Aric Stewart6186b2b2005-05-16 21:37:35 +00002223 /* if uneven pad with a zero in front */
2224 if (strlenW(ptr)%2)
2225 {
2226 byte[2]= '0';
2227 byte[3]= *ptr;
2228 ptr++;
2229 data[count] = (BYTE)strtol(byte,NULL,0);
2230 count ++;
2231 TRACE("Uneven byte count\n");
2232 }
Aric Stewart6e160f12004-06-29 04:07:22 +00002233 while (*ptr)
2234 {
2235 byte[2]= *ptr;
2236 ptr++;
2237 byte[3]= *ptr;
2238 ptr++;
2239 data[count] = (BYTE)strtol(byte,NULL,0);
2240 count ++;
2241 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002242 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002243
Mike McCormackf1d46462006-10-05 13:41:22 +09002244 TRACE("Data %i bytes(%i)\n",*size,count);
Aric Stewart6e160f12004-06-29 04:07:22 +00002245 }
2246 else
2247 {
2248 LPWSTR deformated;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002249 LPWSTR p;
2250 DWORD d = 0;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002251 deformat_string(package, &value[1], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002252
2253 *type=REG_DWORD;
2254 *size = sizeof(DWORD);
Mike McCormackee034ba2005-09-20 11:59:14 +00002255 data = msi_alloc(*size);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002256 p = deformated;
2257 if (*p == '-')
2258 p++;
2259 while (*p)
2260 {
2261 if ( (*p < '0') || (*p > '9') )
2262 break;
2263 d *= 10;
2264 d += (*p - '0');
2265 p++;
2266 }
2267 if (deformated[0] == '-')
2268 d = -d;
2269 *(LPDWORD)data = d;
Mike McCormackf1d46462006-10-05 13:41:22 +09002270 TRACE("DWORD %i\n",*(LPDWORD)data);
Aric Stewart6e160f12004-06-29 04:07:22 +00002271
Mike McCormackee034ba2005-09-20 11:59:14 +00002272 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002273 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002274 }
2275 else
2276 {
Aric Stewart54c67dd2005-01-25 20:17:09 +00002277 static const WCHAR szMulti[] = {'[','~',']',0};
Aric Stewart09b0aba2005-06-09 20:30:59 +00002278 LPCWSTR ptr;
Aric Stewart6e160f12004-06-29 04:07:22 +00002279 *type=REG_SZ;
2280
Aric Stewart401bd3f2004-06-28 20:34:35 +00002281 if (value[0]=='#')
Aric Stewart6e160f12004-06-29 04:07:22 +00002282 {
2283 if (value[1]=='%')
2284 {
2285 ptr = &value[2];
2286 *type=REG_EXPAND_SZ;
2287 }
2288 else
2289 ptr = &value[1];
2290 }
2291 else
Aric Stewart401bd3f2004-06-28 20:34:35 +00002292 ptr=value;
2293
Aric Stewart54c67dd2005-01-25 20:17:09 +00002294 if (strstrW(value,szMulti))
2295 *type = REG_MULTI_SZ;
2296
James Hawkins2f658cb2008-02-04 19:06:53 -06002297 /* remove initial delimiter */
2298 if (!strncmpW(value, szMulti, 3))
2299 ptr = value + 3;
2300
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002301 *size = deformat_string(package, ptr,(LPWSTR*)&data);
James Hawkins2f658cb2008-02-04 19:06:53 -06002302
2303 /* add double NULL terminator */
2304 if (*type == REG_MULTI_SZ)
2305 {
James Hawkins21b4af12008-02-24 20:15:31 -06002306 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2307 data = msi_realloc_zero(data, *size);
James Hawkins2f658cb2008-02-04 19:06:53 -06002308 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002309 }
2310 return data;
2311}
2312
Aric Stewart92ef78e2005-06-21 20:21:18 +00002313static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2314{
2315 MSIPACKAGE *package = (MSIPACKAGE*)param;
2316 static const WCHAR szHCR[] =
2317 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2318 'R','O','O','T','\\',0};
2319 static const WCHAR szHCU[] =
2320 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2321 'U','S','E','R','\\',0};
2322 static const WCHAR szHLM[] =
2323 {'H','K','E','Y','_','L','O','C','A','L','_',
2324 'M','A','C','H','I','N','E','\\',0};
2325 static const WCHAR szHU[] =
2326 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2327
2328 LPSTR value_data = NULL;
2329 HKEY root_key, hkey;
2330 DWORD type,size;
2331 LPWSTR deformated;
2332 LPCWSTR szRoot, component, name, key, value;
Mike McCormack38d67a42005-08-22 09:15:23 +00002333 MSICOMPONENT *comp;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002334 MSIRECORD * uirow;
2335 LPWSTR uikey;
2336 INT root;
2337 BOOL check_first = FALSE;
2338 UINT rc;
2339
2340 ui_progress(package,2,0,0,0);
2341
2342 value = NULL;
2343 key = NULL;
2344 uikey = NULL;
2345 name = NULL;
2346
2347 component = MSI_RecordGetString(row, 6);
Mike McCormack38d67a42005-08-22 09:15:23 +00002348 comp = get_loaded_component(package,component);
Johan Dahlin0946c422005-08-24 10:57:27 +00002349 if (!comp)
2350 return ERROR_SUCCESS;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002351
Mike McCormackd693f462005-10-29 11:36:48 +00002352 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewart92ef78e2005-06-21 20:21:18 +00002353 {
2354 TRACE("Skipping write due to disabled component %s\n",
2355 debugstr_w(component));
2356
Mike McCormack38d67a42005-08-22 09:15:23 +00002357 comp->Action = comp->Installed;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002358
2359 return ERROR_SUCCESS;
2360 }
2361
Mike McCormack38d67a42005-08-22 09:15:23 +00002362 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002363
2364 name = MSI_RecordGetString(row, 4);
2365 if( MSI_RecordIsNull(row,5) && name )
2366 {
2367 /* null values can have special meanings */
2368 if (name[0]=='-' && name[1] == 0)
2369 return ERROR_SUCCESS;
2370 else if ((name[0]=='+' && name[1] == 0) ||
2371 (name[0] == '*' && name[1] == 0))
2372 name = NULL;
2373 check_first = TRUE;
2374 }
2375
2376 root = MSI_RecordGetInteger(row,2);
2377 key = MSI_RecordGetString(row, 3);
2378
2379 /* get the root key */
2380 switch (root)
2381 {
Aric Stewart0713f092005-06-24 11:51:29 +00002382 case -1:
2383 {
2384 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
Mike McCormack062ad502005-09-15 15:04:08 +00002385 LPWSTR all_users = msi_dup_property( package, szALLUSER );
Aric Stewart0713f092005-06-24 11:51:29 +00002386 if (all_users && all_users[0] == '1')
2387 {
2388 root_key = HKEY_LOCAL_MACHINE;
2389 szRoot = szHLM;
2390 }
2391 else
2392 {
2393 root_key = HKEY_CURRENT_USER;
2394 szRoot = szHCU;
2395 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002396 msi_free(all_users);
Aric Stewart0713f092005-06-24 11:51:29 +00002397 }
2398 break;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002399 case 0: root_key = HKEY_CLASSES_ROOT;
2400 szRoot = szHCR;
2401 break;
2402 case 1: root_key = HKEY_CURRENT_USER;
2403 szRoot = szHCU;
2404 break;
2405 case 2: root_key = HKEY_LOCAL_MACHINE;
2406 szRoot = szHLM;
2407 break;
2408 case 3: root_key = HKEY_USERS;
2409 szRoot = szHU;
2410 break;
2411 default:
2412 ERR("Unknown root %i\n",root);
2413 root_key=NULL;
2414 szRoot = NULL;
2415 break;
2416 }
2417 if (!root_key)
2418 return ERROR_SUCCESS;
2419
2420 deformat_string(package, key , &deformated);
2421 size = strlenW(deformated) + strlenW(szRoot) + 1;
Mike McCormackee034ba2005-09-20 11:59:14 +00002422 uikey = msi_alloc(size*sizeof(WCHAR));
Aric Stewart92ef78e2005-06-21 20:21:18 +00002423 strcpyW(uikey,szRoot);
2424 strcatW(uikey,deformated);
2425
2426 if (RegCreateKeyW( root_key, deformated, &hkey))
2427 {
2428 ERR("Could not create key %s\n",debugstr_w(deformated));
Mike McCormackee034ba2005-09-20 11:59:14 +00002429 msi_free(deformated);
2430 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002431 return ERROR_SUCCESS;
2432 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002433 msi_free(deformated);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002434
2435 value = MSI_RecordGetString(row,5);
2436 if (value)
2437 value_data = parse_value(package, value, &type, &size);
2438 else
2439 {
2440 static const WCHAR szEmpty[] = {0};
2441 value_data = (LPSTR)strdupW(szEmpty);
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02002442 size = sizeof(szEmpty);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002443 type = REG_SZ;
2444 }
2445
2446 deformat_string(package, name, &deformated);
2447
Aric Stewart92ef78e2005-06-21 20:21:18 +00002448 if (!check_first)
2449 {
2450 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2451 debugstr_w(uikey));
Mike McCormack16466af2005-07-06 10:33:30 +00002452 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002453 }
2454 else
2455 {
2456 DWORD sz = 0;
2457 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2458 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2459 {
2460 TRACE("value %s of %s checked already exists\n",
2461 debugstr_w(deformated), debugstr_w(uikey));
2462 }
2463 else
2464 {
2465 TRACE("Checked and setting value %s of %s\n",
2466 debugstr_w(deformated), debugstr_w(uikey));
2467 if (deformated || size)
Mike McCormack16466af2005-07-06 10:33:30 +00002468 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002469 }
2470 }
2471 RegCloseKey(hkey);
2472
2473 uirow = MSI_CreateRecord(3);
2474 MSI_RecordSetStringW(uirow,2,deformated);
2475 MSI_RecordSetStringW(uirow,1,uikey);
2476
2477 if (type == REG_SZ)
2478 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2479 else
2480 MSI_RecordSetStringW(uirow,3,value);
2481
2482 ui_actiondata(package,szWriteRegistryValues,uirow);
2483 msiobj_release( &uirow->hdr );
2484
Mike McCormackee034ba2005-09-20 11:59:14 +00002485 msi_free(value_data);
2486 msi_free(deformated);
2487 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002488
2489 return ERROR_SUCCESS;
2490}
2491
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002492static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00002493{
2494 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002495 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002496 static const WCHAR ExecSeqQuery[] =
2497 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002498 '`','R','e','g','i','s','t','r','y','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00002499
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002500 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002501 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002502 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00002503
Aric Stewartd2c395a2004-07-06 18:48:15 +00002504 /* increment progress bar each time action data is sent */
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002505 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002506
Aric Stewart92ef78e2005-06-21 20:21:18 +00002507 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002508
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002509 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002510 return rc;
2511}
2512
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002513static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002514{
Aric Stewart9cd707d2005-05-27 19:24:22 +00002515 package->script->CurrentlyScripting = TRUE;
2516
Aric Stewart7d3e5972004-07-04 00:36:58 +00002517 return ERROR_SUCCESS;
2518}
2519
Aric Stewartae1aa322004-12-27 19:02:59 +00002520
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002521static UINT ACTION_InstallValidate(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002522{
Mike McCormack38d67a42005-08-22 09:15:23 +00002523 MSICOMPONENT *comp;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002524 DWORD progress = 0;
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002525 DWORD total = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002526 static const WCHAR q1[]=
2527 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002528 '`','R','e','g','i','s','t','r','y','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002529 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002530 MSIQUERY * view;
Mike McCormack1da28582005-08-22 14:09:17 +00002531 MSIFEATURE *feature;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002532 MSIFILE *file;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002533
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002534 TRACE("InstallValidate\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002535
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002536 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002537 if (rc == ERROR_SUCCESS)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002538 {
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002539 MSI_IterateRecords( view, &progress, NULL, package );
2540 msiobj_release( &view->hdr );
2541 total += progress * REG_PROGRESS_VALUE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002542 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002543
Mike McCormack38d67a42005-08-22 09:15:23 +00002544 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Mike McCormack38d67a42005-08-22 09:15:23 +00002545 total += COMPONENT_PROGRESS_VALUE;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002546
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002547 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002548 total += file->FileSize;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002549
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002550 ui_progress(package,0,total,0,0);
Aric Stewart7d3e5972004-07-04 00:36:58 +00002551
Mike McCormack1da28582005-08-22 14:09:17 +00002552 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002553 {
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002554 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2555 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2556 feature->ActionRequest);
2557 }
2558
Aric Stewart7d3e5972004-07-04 00:36:58 +00002559 return ERROR_SUCCESS;
2560}
2561
Aric Stewartc79f4e22005-06-22 18:03:08 +00002562static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2563{
2564 MSIPACKAGE* package = (MSIPACKAGE*)param;
2565 LPCWSTR cond = NULL;
2566 LPCWSTR message = NULL;
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002567 UINT r;
2568
Aric Stewartc79f4e22005-06-22 18:03:08 +00002569 static const WCHAR title[]=
2570 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2571
2572 cond = MSI_RecordGetString(row,1);
2573
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002574 r = MSI_EvaluateConditionW(package,cond);
2575 if (r == MSICONDITION_FALSE)
Aric Stewartc79f4e22005-06-22 18:03:08 +00002576 {
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002577 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2578 {
2579 LPWSTR deformated;
2580 message = MSI_RecordGetString(row,2);
2581 deformat_string(package,message,&deformated);
2582 MessageBoxW(NULL,deformated,title,MB_OK);
2583 msi_free(deformated);
2584 }
2585
2586 return ERROR_INSTALL_FAILURE;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002587 }
2588
2589 return ERROR_SUCCESS;
2590}
2591
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002592static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
Aric Stewart5b936ca2004-07-06 18:47:09 +00002593{
2594 UINT rc;
Mike McCormackf3c8b832004-07-19 19:35:05 +00002595 MSIQUERY * view = NULL;
Aric Stewart8e233e92005-03-01 11:45:19 +00002596 static const WCHAR ExecSeqQuery[] =
2597 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002598 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002599
Aric Stewart5b936ca2004-07-06 18:47:09 +00002600 TRACE("Checking launch conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002601
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002602 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart5b936ca2004-07-06 18:47:09 +00002603 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002604 return ERROR_SUCCESS;
Aric Stewart5b936ca2004-07-06 18:47:09 +00002605
Aric Stewartc79f4e22005-06-22 18:03:08 +00002606 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002607 msiobj_release(&view->hdr);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002608
Aric Stewart5b936ca2004-07-06 18:47:09 +00002609 return rc;
2610}
Aric Stewart7d3e5972004-07-04 00:36:58 +00002611
Mike McCormack38d67a42005-08-22 09:15:23 +00002612static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
Aric Stewartb942e182004-07-06 18:50:02 +00002613{
Aric Stewartb942e182004-07-06 18:50:02 +00002614
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002615 if (!cmp->KeyPath)
James Hawkins8cedb212007-03-29 02:38:57 -05002616 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002617
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002618 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
Aric Stewartb942e182004-07-06 18:50:02 +00002619 {
Aric Stewart6269f002005-01-17 13:40:39 +00002620 MSIRECORD * row = 0;
Mike McCormack0b352c72005-06-02 10:29:57 +00002621 UINT root,len;
Aric Stewart09b0aba2005-06-09 20:30:59 +00002622 LPWSTR deformated,buffer,deformated_name;
2623 LPCWSTR key,name;
Aric Stewart8e233e92005-03-01 11:45:19 +00002624 static const WCHAR ExecSeqQuery[] =
2625 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002626 '`','R','e','g','i','s','t','r','y','`',' ',
2627 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2628 ' ','=',' ' ,'\'','%','s','\'',0 };
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002629 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00002630 static const WCHAR fmt2[]=
2631 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
Aric Stewart6269f002005-01-17 13:40:39 +00002632
Mike McCormack0b352c72005-06-02 10:29:57 +00002633 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2634 if (!row)
Aric Stewart6269f002005-01-17 13:40:39 +00002635 return NULL;
2636
Aric Stewart6269f002005-01-17 13:40:39 +00002637 root = MSI_RecordGetInteger(row,2);
Aric Stewart09b0aba2005-06-09 20:30:59 +00002638 key = MSI_RecordGetString(row, 3);
2639 name = MSI_RecordGetString(row, 4);
Aric Stewart6269f002005-01-17 13:40:39 +00002640 deformat_string(package, key , &deformated);
2641 deformat_string(package, name, &deformated_name);
2642
Ulrich Czekallae15e5172005-03-08 16:44:51 +00002643 len = strlenW(deformated) + 6;
Aric Stewart6269f002005-01-17 13:40:39 +00002644 if (deformated_name)
2645 len+=strlenW(deformated_name);
2646
Mike McCormackee034ba2005-09-20 11:59:14 +00002647 buffer = msi_alloc( len *sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00002648
2649 if (deformated_name)
2650 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2651 else
2652 sprintfW(buffer,fmt,root,deformated);
2653
Mike McCormackee034ba2005-09-20 11:59:14 +00002654 msi_free(deformated);
2655 msi_free(deformated_name);
Aric Stewart6269f002005-01-17 13:40:39 +00002656 msiobj_release(&row->hdr);
Aric Stewart6269f002005-01-17 13:40:39 +00002657
2658 return buffer;
2659 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002660 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewart6269f002005-01-17 13:40:39 +00002661 {
2662 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
Aric Stewartfa384f62004-12-22 18:46:17 +00002663 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002664 }
2665 else
2666 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002667 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
Aric Stewartfcb20c52004-07-06 18:51:16 +00002668
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002669 if (file)
2670 return strdupW( file->TargetPath );
Aric Stewartb942e182004-07-06 18:50:02 +00002671 }
Aric Stewartfa384f62004-12-22 18:46:17 +00002672 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002673}
2674
Stefan Huehnerac6f5622005-06-20 14:18:03 +00002675static HKEY openSharedDLLsKey(void)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002676{
2677 HKEY hkey=0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002678 static const WCHAR path[] =
2679 {'S','o','f','t','w','a','r','e','\\',
2680 'M','i','c','r','o','s','o','f','t','\\',
2681 'W','i','n','d','o','w','s','\\',
2682 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2683 'S','h','a','r','e','d','D','L','L','s',0};
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002684
2685 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2686 return hkey;
2687}
2688
2689static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2690{
2691 HKEY hkey;
2692 DWORD count=0;
2693 DWORD type;
2694 DWORD sz = sizeof(count);
2695 DWORD rc;
2696
2697 hkey = openSharedDLLsKey();
2698 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2699 if (rc != ERROR_SUCCESS)
2700 count = 0;
2701 RegCloseKey(hkey);
2702 return count;
2703}
2704
2705static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2706{
2707 HKEY hkey;
2708
2709 hkey = openSharedDLLsKey();
2710 if (count > 0)
Mike McCormack4db02cd2005-09-15 14:58:38 +00002711 msi_reg_set_val_dword( hkey, path, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002712 else
2713 RegDeleteValueW(hkey,path);
2714 RegCloseKey(hkey);
2715 return count;
2716}
2717
2718/*
2719 * Return TRUE if the count should be written out and FALSE if not
2720 */
Mike McCormack38d67a42005-08-22 09:15:23 +00002721static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002722{
Mike McCormack1da28582005-08-22 14:09:17 +00002723 MSIFEATURE *feature;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002724 INT count = 0;
2725 BOOL write = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002726
2727 /* only refcount DLLs */
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002728 if (comp->KeyPath == NULL ||
Mike McCormack38d67a42005-08-22 09:15:23 +00002729 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2730 comp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002731 write = FALSE;
2732 else
2733 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002734 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002735 write = (count > 0);
2736
Mike McCormack38d67a42005-08-22 09:15:23 +00002737 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002738 write = TRUE;
2739 }
2740
2741 /* increment counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002742 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002743 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002744 ComponentList *cl;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002745
Mike McCormack1da28582005-08-22 14:09:17 +00002746 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002747 continue;
2748
Mike McCormack1da28582005-08-22 14:09:17 +00002749 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002750 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002751 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002752 count++;
2753 }
2754 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002755
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002756 /* decrement counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002757 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002758 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002759 ComponentList *cl;
2760
Mike McCormack1da28582005-08-22 14:09:17 +00002761 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002762 continue;
2763
Mike McCormack1da28582005-08-22 14:09:17 +00002764 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002765 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002766 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002767 count--;
2768 }
2769 }
2770
2771 /* ref count all the files in the component */
2772 if (write)
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002773 {
2774 MSIFILE *file;
2775
2776 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002777 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002778 if (file->Component == comp)
2779 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002780 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002781 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002782
Austin English5644f052008-04-07 14:44:23 -05002783 /* add a count for permanent */
Mike McCormack38d67a42005-08-22 09:15:23 +00002784 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002785 count ++;
2786
Mike McCormack38d67a42005-08-22 09:15:23 +00002787 comp->RefCount = count;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002788
2789 if (write)
Mike McCormack38d67a42005-08-22 09:15:23 +00002790 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002791}
2792
Aric Stewart2cf222f2004-07-06 19:00:23 +00002793/*
2794 * Ok further analysis makes me think that this work is
2795 * actually done in the PublishComponents and PublishFeatures
Mike McCormack3ece2462004-07-09 19:33:25 +00002796 * step, and not here. It appears like the keypath and all that is
2797 * resolved in this step, however actually written in the Publish steps.
Alexandre Julliard77b12762004-07-09 19:43:29 +00002798 * But we will leave it here for now because it is unclear
Aric Stewart2cf222f2004-07-06 19:00:23 +00002799 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002800static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
Aric Stewartb942e182004-07-06 18:50:02 +00002801{
Aric Stewart68b07492005-01-25 11:05:37 +00002802 WCHAR squished_pc[GUID_SIZE];
2803 WCHAR squished_cc[GUID_SIZE];
Aric Stewartb942e182004-07-06 18:50:02 +00002804 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00002805 MSICOMPONENT *comp;
Aric Stewart68b07492005-01-25 11:05:37 +00002806 HKEY hkey=0,hkey2=0;
Aric Stewartb942e182004-07-06 18:50:02 +00002807
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002808 TRACE("\n");
2809
Aric Stewartb942e182004-07-06 18:50:02 +00002810 /* writes the Component and Features values to the registry */
Aric Stewartb942e182004-07-06 18:50:02 +00002811
Aric Stewart68b07492005-01-25 11:05:37 +00002812 rc = MSIREG_OpenComponents(&hkey);
Aric Stewartb942e182004-07-06 18:50:02 +00002813 if (rc != ERROR_SUCCESS)
Mike McCormackfe8cd382006-03-09 14:21:37 +09002814 return rc;
2815
Aric Stewartadaef112005-07-07 20:27:06 +00002816 squash_guid(package->ProductCode,squished_pc);
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002817 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
Mike McCormack38d67a42005-08-22 09:15:23 +00002818
2819 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewartb942e182004-07-06 18:50:02 +00002820 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002821 MSIRECORD * uirow;
2822
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002823 ui_progress(package,2,0,0,0);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002824 if (!comp->ComponentId)
2825 continue;
Aric Stewartb942e182004-07-06 18:50:02 +00002826
Mike McCormackfe8cd382006-03-09 14:21:37 +09002827 squash_guid(comp->ComponentId,squished_cc);
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002828
Mike McCormackfe8cd382006-03-09 14:21:37 +09002829 msi_free(comp->FullKeypath);
2830 comp->FullKeypath = resolve_keypath( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002831
Mike McCormackfe8cd382006-03-09 14:21:37 +09002832 /* do the refcounting */
2833 ACTION_RefCountComponent( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002834
Mike McCormackfe8cd382006-03-09 14:21:37 +09002835 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
Mike McCormack38d67a42005-08-22 09:15:23 +00002836 debugstr_w(comp->Component),
Aric Stewartc5a14432005-05-18 17:46:12 +00002837 debugstr_w(squished_cc),
Mike McCormackfe8cd382006-03-09 14:21:37 +09002838 debugstr_w(comp->FullKeypath),
Mike McCormack38d67a42005-08-22 09:15:23 +00002839 comp->RefCount);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002840 /*
2841 * Write the keypath out if the component is to be registered
Austin English5644f052008-04-07 14:44:23 -05002842 * and delete the key if the component is to be unregistered
Mike McCormackfe8cd382006-03-09 14:21:37 +09002843 */
2844 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2845 {
2846 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2847 if (rc != ERROR_SUCCESS)
2848 continue;
2849
2850 if (!comp->FullKeypath)
2851 continue;
2852
2853 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2854
2855 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartfa384f62004-12-22 18:46:17 +00002856 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002857 static const WCHAR szPermKey[] =
2858 { '0','0','0','0','0','0','0','0','0','0','0','0',
2859 '0','0','0','0','0','0','0','0','0','0','0','0',
2860 '0','0','0','0','0','0','0','0',0 };
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002861
Mike McCormackfe8cd382006-03-09 14:21:37 +09002862 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002863 }
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002864
Mike McCormackfe8cd382006-03-09 14:21:37 +09002865 RegCloseKey(hkey2);
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002866
2867 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, &hkey2, TRUE);
2868 if (rc != ERROR_SUCCESS)
2869 continue;
2870
2871 msi_reg_set_val_str(hkey2, squished_pc, comp->FullKeypath);
2872 RegCloseKey(hkey2);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002873 }
2874 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2875 {
2876 DWORD res;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002877
Mike McCormackfe8cd382006-03-09 14:21:37 +09002878 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2879 if (rc != ERROR_SUCCESS)
2880 continue;
2881
2882 RegDeleteValueW(hkey2,squished_pc);
2883
2884 /* if the key is empty delete it */
2885 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2886 RegCloseKey(hkey2);
2887 if (res == ERROR_NO_MORE_ITEMS)
2888 RegDeleteKeyW(hkey,squished_cc);
2889
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002890 MSIREG_DeleteUserDataComponentKey(comp->ComponentId);
Aric Stewartb942e182004-07-06 18:50:02 +00002891 }
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002892
2893 /* UI stuff */
2894 uirow = MSI_CreateRecord(3);
2895 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2896 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2897 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2898 ui_actiondata(package,szProcessComponents,uirow);
2899 msiobj_release( &uirow->hdr );
2900 }
Aric Stewartb942e182004-07-06 18:50:02 +00002901 RegCloseKey(hkey);
2902 return rc;
2903}
2904
Aric Stewart6e821732005-03-30 10:19:08 +00002905typedef struct {
2906 CLSID clsid;
2907 LPWSTR source;
2908
2909 LPWSTR path;
2910 ITypeLib *ptLib;
2911} typelib_struct;
2912
Mike McCormackf9acfe62005-06-07 20:29:51 +00002913static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
Aric Stewart6e821732005-03-30 10:19:08 +00002914 LPWSTR lpszName, LONG_PTR lParam)
2915{
2916 TLIBATTR *attr;
2917 typelib_struct *tl_struct = (typelib_struct*) lParam;
2918 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2919 int sz;
2920 HRESULT res;
2921
2922 if (!IS_INTRESOURCE(lpszName))
2923 {
2924 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2925 return TRUE;
2926 }
2927
2928 sz = strlenW(tl_struct->source)+4;
2929 sz *= sizeof(WCHAR);
2930
Mike McCormack2acf8002006-05-25 11:41:39 +09002931 if ((INT_PTR)lpszName == 1)
Aric Stewartca8c4e42005-06-02 15:13:57 +00002932 tl_struct->path = strdupW(tl_struct->source);
2933 else
2934 {
Mike McCormackee034ba2005-09-20 11:59:14 +00002935 tl_struct->path = msi_alloc(sz);
Aric Stewartca8c4e42005-06-02 15:13:57 +00002936 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2937 }
Aric Stewart6e821732005-03-30 10:19:08 +00002938
2939 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2940 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2941 if (!SUCCEEDED(res))
2942 {
Mike McCormackee034ba2005-09-20 11:59:14 +00002943 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00002944 tl_struct->path = NULL;
2945
2946 return TRUE;
2947 }
2948
2949 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2950 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2951 {
2952 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2953 return FALSE;
2954 }
2955
Mike McCormackee034ba2005-09-20 11:59:14 +00002956 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00002957 tl_struct->path = NULL;
2958
2959 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2960 ITypeLib_Release(tl_struct->ptLib);
2961
2962 return TRUE;
2963}
2964
Aric Stewart234dc4b2005-06-22 18:27:34 +00002965static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2966{
2967 MSIPACKAGE* package = (MSIPACKAGE*)param;
2968 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00002969 MSICOMPONENT *comp;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002970 MSIFILE *file;
Aric Stewart234dc4b2005-06-22 18:27:34 +00002971 typelib_struct tl_struct;
2972 HMODULE module;
2973 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2974
2975 component = MSI_RecordGetString(row,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00002976 comp = get_loaded_component(package,component);
2977 if (!comp)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002978 return ERROR_SUCCESS;
2979
Mike McCormackd693f462005-10-29 11:36:48 +00002980 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewart234dc4b2005-06-22 18:27:34 +00002981 {
2982 TRACE("Skipping typelib reg due to disabled component\n");
2983
Mike McCormack38d67a42005-08-22 09:15:23 +00002984 comp->Action = comp->Installed;
Aric Stewart234dc4b2005-06-22 18:27:34 +00002985
2986 return ERROR_SUCCESS;
2987 }
2988
Mike McCormack38d67a42005-08-22 09:15:23 +00002989 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart234dc4b2005-06-22 18:27:34 +00002990
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002991 file = get_loaded_file( package, comp->KeyPath );
2992 if (!file)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002993 return ERROR_SUCCESS;
2994
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002995 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
Mike McCormack51c66182005-10-27 12:36:12 +00002996 if (module)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002997 {
Mike McCormack51c66182005-10-27 12:36:12 +00002998 LPCWSTR guid;
2999 guid = MSI_RecordGetString(row,1);
3000 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003001 tl_struct.source = strdupW( file->TargetPath );
Aric Stewart234dc4b2005-06-22 18:27:34 +00003002 tl_struct.path = NULL;
3003
3004 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3005 (LONG_PTR)&tl_struct);
3006
Mike McCormack51c66182005-10-27 12:36:12 +00003007 if (tl_struct.path)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003008 {
3009 LPWSTR help = NULL;
3010 LPCWSTR helpid;
3011 HRESULT res;
3012
3013 helpid = MSI_RecordGetString(row,6);
3014
3015 if (helpid)
James Hawkins8cedb212007-03-29 02:38:57 -05003016 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003017 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
Mike McCormackee034ba2005-09-20 11:59:14 +00003018 msi_free(help);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003019
3020 if (!SUCCEEDED(res))
3021 ERR("Failed to register type library %s\n",
3022 debugstr_w(tl_struct.path));
3023 else
3024 {
3025 ui_actiondata(package,szRegisterTypeLibraries,row);
3026
3027 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3028 }
3029
3030 ITypeLib_Release(tl_struct.ptLib);
Mike McCormackee034ba2005-09-20 11:59:14 +00003031 msi_free(tl_struct.path);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003032 }
3033 else
3034 ERR("Failed to load type library %s\n",
3035 debugstr_w(tl_struct.source));
3036
3037 FreeLibrary(module);
Mike McCormackee034ba2005-09-20 11:59:14 +00003038 msi_free(tl_struct.source);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003039 }
3040 else
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003041 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
Aric Stewart234dc4b2005-06-22 18:27:34 +00003042
3043 return ERROR_SUCCESS;
3044}
3045
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003046static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
Aric Stewartfcb20c52004-07-06 18:51:16 +00003047{
3048 /*
Mike McCormackc90c7812004-07-09 22:58:27 +00003049 * OK this is a bit confusing.. I am given a _Component key and I believe
Aric Stewartfcb20c52004-07-06 18:51:16 +00003050 * that the file that is being registered as a type library is the "key file
Mike McCormackc90c7812004-07-09 22:58:27 +00003051 * of that component" which I interpret to mean "The file in the KeyPath of
3052 * that component".
Aric Stewartfcb20c52004-07-06 18:51:16 +00003053 */
3054 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003055 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003056 static const WCHAR Query[] =
3057 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003058 '`','T','y','p','e','L','i','b','`',0};
Aric Stewartfcb20c52004-07-06 18:51:16 +00003059
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003060 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003061 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00003062 return ERROR_SUCCESS;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003063
Aric Stewart234dc4b2005-06-22 18:27:34 +00003064 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003065 msiobj_release(&view->hdr);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003066 return rc;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003067}
3068
Aric Stewart9adacf62005-06-24 11:58:21 +00003069static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003070{
Aric Stewart9adacf62005-06-24 11:58:21 +00003071 MSIPACKAGE *package = (MSIPACKAGE*)param;
Mike McCormack477bce32006-01-16 20:38:28 +01003072 LPWSTR target_file, target_folder, filename;
Robert Shearman4ac85672006-02-22 16:31:00 +00003073 LPCWSTR buffer, extension;
Mike McCormack38d67a42005-08-22 09:15:23 +00003074 MSICOMPONENT *comp;
Aric Stewart9adacf62005-06-24 11:58:21 +00003075 static const WCHAR szlnk[]={'.','l','n','k',0};
Mike McCormack20c57462006-05-24 17:41:04 +09003076 IShellLinkW *sl = NULL;
3077 IPersistFile *pf = NULL;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003078 HRESULT res;
3079
Aric Stewart9adacf62005-06-24 11:58:21 +00003080 buffer = MSI_RecordGetString(row,4);
Mike McCormack38d67a42005-08-22 09:15:23 +00003081 comp = get_loaded_component(package,buffer);
3082 if (!comp)
Aric Stewart9adacf62005-06-24 11:58:21 +00003083 return ERROR_SUCCESS;
3084
Mike McCormackd693f462005-10-29 11:36:48 +00003085 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003086 {
3087 TRACE("Skipping shortcut creation due to disabled component\n");
3088
Mike McCormack38d67a42005-08-22 09:15:23 +00003089 comp->Action = comp->Installed;
Aric Stewart9adacf62005-06-24 11:58:21 +00003090
3091 return ERROR_SUCCESS;
3092 }
3093
Mike McCormack38d67a42005-08-22 09:15:23 +00003094 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart9adacf62005-06-24 11:58:21 +00003095
3096 ui_actiondata(package,szCreateShortcuts,row);
3097
3098 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3099 &IID_IShellLinkW, (LPVOID *) &sl );
3100
Mike McCormack20c57462006-05-24 17:41:04 +09003101 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003102 {
Mike McCormack20c57462006-05-24 17:41:04 +09003103 ERR("CLSID_ShellLink not available\n");
3104 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003105 }
3106
3107 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
Mike McCormack20c57462006-05-24 17:41:04 +09003108 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003109 {
Mike McCormack20c57462006-05-24 17:41:04 +09003110 ERR("QueryInterface(IID_IPersistFile) failed\n");
3111 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003112 }
3113
3114 buffer = MSI_RecordGetString(row,2);
James Hawkins8cedb212007-03-29 02:38:57 -05003115 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
Aric Stewart9adacf62005-06-24 11:58:21 +00003116
Austin English5644f052008-04-07 14:44:23 -05003117 /* may be needed because of a bug somewhere else */
Aric Stewart9adacf62005-06-24 11:58:21 +00003118 create_full_pathW(target_folder);
3119
Mike McCormack477bce32006-01-16 20:38:28 +01003120 filename = msi_dup_record_field( row, 3 );
Aric Stewart9adacf62005-06-24 11:58:21 +00003121 reduce_to_longfilename(filename);
Robert Shearman4ac85672006-02-22 16:31:00 +00003122
3123 extension = strchrW(filename,'.');
3124 if (!extension || strcmpiW(extension,szlnk))
3125 {
3126 int len = strlenW(filename);
3127 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3128 memcpy(filename + len, szlnk, sizeof(szlnk));
3129 }
Aric Stewart9adacf62005-06-24 11:58:21 +00003130 target_file = build_directory_name(2, target_folder, filename);
Mike McCormackee034ba2005-09-20 11:59:14 +00003131 msi_free(target_folder);
Mike McCormack477bce32006-01-16 20:38:28 +01003132 msi_free(filename);
Aric Stewart9adacf62005-06-24 11:58:21 +00003133
3134 buffer = MSI_RecordGetString(row,5);
3135 if (strchrW(buffer,'['))
3136 {
3137 LPWSTR deformated;
3138 deformat_string(package,buffer,&deformated);
3139 IShellLinkW_SetPath(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003140 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003141 }
3142 else
3143 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003144 FIXME("poorly handled shortcut format, advertised shortcut\n");
Mike McCormack566c69e2005-09-22 10:49:17 +00003145 IShellLinkW_SetPath(sl,comp->FullKeypath);
Aric Stewart9adacf62005-06-24 11:58:21 +00003146 }
3147
3148 if (!MSI_RecordIsNull(row,6))
3149 {
3150 LPWSTR deformated;
3151 buffer = MSI_RecordGetString(row,6);
3152 deformat_string(package,buffer,&deformated);
3153 IShellLinkW_SetArguments(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003154 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003155 }
3156
3157 if (!MSI_RecordIsNull(row,7))
3158 {
3159 buffer = MSI_RecordGetString(row,7);
3160 IShellLinkW_SetDescription(sl,buffer);
3161 }
3162
3163 if (!MSI_RecordIsNull(row,8))
3164 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3165
3166 if (!MSI_RecordIsNull(row,9))
3167 {
Mike McCormack75658d72005-09-22 10:33:57 +00003168 LPWSTR Path;
Aric Stewart9adacf62005-06-24 11:58:21 +00003169 INT index;
3170
3171 buffer = MSI_RecordGetString(row,9);
3172
Mike McCormack75658d72005-09-22 10:33:57 +00003173 Path = build_icon_path(package,buffer);
Aric Stewart9adacf62005-06-24 11:58:21 +00003174 index = MSI_RecordGetInteger(row,10);
3175
Robert Shearmanab378802006-08-03 20:24:10 +01003176 /* no value means 0 */
3177 if (index == MSI_NULL_INTEGER)
3178 index = 0;
3179
Aric Stewart9adacf62005-06-24 11:58:21 +00003180 IShellLinkW_SetIconLocation(sl,Path,index);
Mike McCormackee034ba2005-09-20 11:59:14 +00003181 msi_free(Path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003182 }
3183
3184 if (!MSI_RecordIsNull(row,11))
3185 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3186
3187 if (!MSI_RecordIsNull(row,12))
3188 {
3189 LPWSTR Path;
3190 buffer = MSI_RecordGetString(row,12);
James Hawkins8cedb212007-03-29 02:38:57 -05003191 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
Mike McCormack43f7f3e2006-07-27 23:18:15 +09003192 if (Path)
3193 IShellLinkW_SetWorkingDirectory(sl,Path);
Mike McCormackee034ba2005-09-20 11:59:14 +00003194 msi_free(Path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003195 }
3196
3197 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3198 IPersistFile_Save(pf,target_file,FALSE);
3199
Mike McCormackee034ba2005-09-20 11:59:14 +00003200 msi_free(target_file);
Aric Stewart9adacf62005-06-24 11:58:21 +00003201
Mike McCormack20c57462006-05-24 17:41:04 +09003202err:
3203 if (pf)
3204 IPersistFile_Release( pf );
3205 if (sl)
3206 IShellLinkW_Release( sl );
Aric Stewart9adacf62005-06-24 11:58:21 +00003207
3208 return ERROR_SUCCESS;
3209}
3210
3211static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3212{
3213 UINT rc;
3214 HRESULT res;
3215 MSIQUERY * view;
3216 static const WCHAR Query[] =
3217 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3218 '`','S','h','o','r','t','c','u','t','`',0};
3219
Aric Stewart9adacf62005-06-24 11:58:21 +00003220 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3221 if (rc != ERROR_SUCCESS)
3222 return ERROR_SUCCESS;
3223
Aric Stewart2cf222f2004-07-06 19:00:23 +00003224 res = CoInitialize( NULL );
3225 if (FAILED (res))
3226 {
3227 ERR("CoInitialize failed\n");
3228 return ERROR_FUNCTION_FAILED;
3229 }
3230
Aric Stewart9adacf62005-06-24 11:58:21 +00003231 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003232 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003233
Aric Stewart2cf222f2004-07-06 19:00:23 +00003234 CoUninitialize();
3235
3236 return rc;
3237}
3238
Aric Stewart916ef942005-06-22 18:42:19 +00003239static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3240{
3241 MSIPACKAGE* package = (MSIPACKAGE*)param;
3242 HANDLE the_file;
Mike McCormack75658d72005-09-22 10:33:57 +00003243 LPWSTR FilePath;
3244 LPCWSTR FileName;
Aric Stewart916ef942005-06-22 18:42:19 +00003245 CHAR buffer[1024];
3246 DWORD sz;
3247 UINT rc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003248 MSIRECORD *uirow;
Aric Stewart916ef942005-06-22 18:42:19 +00003249
3250 FileName = MSI_RecordGetString(row,1);
3251 if (!FileName)
3252 {
3253 ERR("Unable to get FileName\n");
3254 return ERROR_SUCCESS;
3255 }
3256
Mike McCormack75658d72005-09-22 10:33:57 +00003257 FilePath = build_icon_path(package,FileName);
Aric Stewart916ef942005-06-22 18:42:19 +00003258
3259 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3260
3261 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3262 FILE_ATTRIBUTE_NORMAL, NULL);
3263
3264 if (the_file == INVALID_HANDLE_VALUE)
3265 {
3266 ERR("Unable to create file %s\n",debugstr_w(FilePath));
Mike McCormackee034ba2005-09-20 11:59:14 +00003267 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003268 return ERROR_SUCCESS;
3269 }
3270
3271 do
3272 {
3273 DWORD write;
3274 sz = 1024;
3275 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3276 if (rc != ERROR_SUCCESS)
3277 {
3278 ERR("Failed to get stream\n");
3279 CloseHandle(the_file);
3280 DeleteFileW(FilePath);
3281 break;
3282 }
3283 WriteFile(the_file,buffer,sz,&write,NULL);
3284 } while (sz == 1024);
3285
Mike McCormackee034ba2005-09-20 11:59:14 +00003286 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003287
3288 CloseHandle(the_file);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003289
3290 uirow = MSI_CreateRecord(1);
3291 MSI_RecordSetStringW(uirow,1,FileName);
3292 ui_actiondata(package,szPublishProduct,uirow);
3293 msiobj_release( &uirow->hdr );
3294
Aric Stewart916ef942005-06-22 18:42:19 +00003295 return ERROR_SUCCESS;
3296}
Aric Stewart2cf222f2004-07-06 19:00:23 +00003297
James Hawkinsa2df31a2007-07-02 20:21:26 -07003298static BOOL msi_check_publish(MSIPACKAGE *package)
3299{
3300 MSIFEATURE *feature;
3301
3302 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3303 {
3304 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3305 return TRUE;
3306 }
3307
3308 return FALSE;
3309}
3310
Aric Stewart2cf222f2004-07-06 19:00:23 +00003311/*
3312 * 99% of the work done here is only done for
3313 * advertised installs. However this is where the
3314 * Icon table is processed and written out
Francois Gouget817c5202004-07-16 19:15:40 +00003315 * so that is what I am going to do here.
Aric Stewart2cf222f2004-07-06 19:00:23 +00003316 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003317static UINT ACTION_PublishProduct(MSIPACKAGE *package)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003318{
3319 UINT rc;
James Hawkinsd52f48f2008-03-06 16:12:40 -06003320 LPWSTR packname;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003321 MSIQUERY * view;
James Hawkins5e46fc92007-07-02 20:20:20 -07003322 MSISOURCELISTINFO *info;
3323 MSIMEDIADISK *disk;
Aric Stewart8e233e92005-03-01 11:45:19 +00003324 static const WCHAR Query[]=
3325 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003326 '`','I','c','o','n','`',0};
Aric Stewart6269f002005-01-17 13:40:39 +00003327 /* for registry stuff */
Aric Stewart68b07492005-01-25 11:05:37 +00003328 HKEY hkey=0;
3329 HKEY hukey=0;
James Hawkinsc18b7752007-06-26 19:22:46 -07003330 HKEY hudkey=0, props=0;
James Hawkins3de00142008-02-21 00:02:46 -06003331 HKEY source;
Aric Stewart6957e4a2005-06-08 19:16:45 +00003332 static const WCHAR szProductLanguage[] =
3333 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
Aric Stewart6957e4a2005-06-08 19:16:45 +00003334 static const WCHAR szARPProductIcon[] =
3335 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
Aric Stewartc28bb542005-06-09 15:49:11 +00003336 static const WCHAR szProductVersion[] =
3337 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
James Hawkins3de00142008-02-21 00:02:46 -06003338 static const WCHAR szSourceList[] =
3339 {'S','o','u','r','c','e','L','i','s','t',0};
3340 static const WCHAR szEmpty[] = {0};
Aric Stewart6957e4a2005-06-08 19:16:45 +00003341 DWORD langid;
Aric Stewart6269f002005-01-17 13:40:39 +00003342 LPWSTR buffer;
3343 DWORD size;
Aric Stewart68b07492005-01-25 11:05:37 +00003344 MSIHANDLE hDb, hSumInfo;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003345
James Hawkinsa2df31a2007-07-02 20:21:26 -07003346 /* FIXME: also need to publish if the product is in advertise mode */
3347 if (!msi_check_publish(package))
3348 return ERROR_SUCCESS;
3349
Aric Stewart916ef942005-06-22 18:42:19 +00003350 /* write out icon files */
3351
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003352 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewart916ef942005-06-22 18:42:19 +00003353 if (rc == ERROR_SUCCESS)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003354 {
Aric Stewart916ef942005-06-22 18:42:19 +00003355 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003356 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003357 }
3358
Francois Gougetda8b3dd2005-01-26 21:09:04 +00003359 /* ok there is a lot more done here but i need to figure out what */
Aric Stewart916ef942005-06-22 18:42:19 +00003360
James Hawkins82517d62008-04-05 00:10:02 -05003361 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3362 {
3363 rc = MSIREG_OpenLocalClassesProductKey(package->ProductCode, &hukey, TRUE);
3364 if (rc != ERROR_SUCCESS)
3365 goto end;
James Hawkinsbcba82d2008-04-05 06:02:04 -05003366
3367 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
3368 if (rc != ERROR_SUCCESS)
3369 goto end;
James Hawkins82517d62008-04-05 00:10:02 -05003370 }
3371 else
3372 {
3373 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3374 if (rc != ERROR_SUCCESS)
3375 goto end;
Aric Stewart6269f002005-01-17 13:40:39 +00003376
James Hawkins82517d62008-04-05 00:10:02 -05003377 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3378 if (rc != ERROR_SUCCESS)
3379 goto end;
James Hawkinsbcba82d2008-04-05 06:02:04 -05003380
3381 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
3382 if (rc != ERROR_SUCCESS)
3383 goto end;
James Hawkins82517d62008-04-05 00:10:02 -05003384 }
Aric Stewart6269f002005-01-17 13:40:39 +00003385
James Hawkins3de00142008-02-21 00:02:46 -06003386 rc = RegCreateKeyW(hukey, szSourceList, &source);
3387 if (rc != ERROR_SUCCESS)
3388 goto end;
3389
3390 RegCloseKey(source);
3391
James Hawkinsc18b7752007-06-26 19:22:46 -07003392 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3393 if (rc != ERROR_SUCCESS)
3394 goto end;
3395
Mike McCormack062ad502005-09-15 15:04:08 +00003396 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
Mike McCormack4db02cd2005-09-15 14:58:38 +00003397 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00003398 msi_free(buffer);
Aric Stewart6957e4a2005-06-08 19:16:45 +00003399
Mike McCormack74f0de92005-09-29 10:32:39 +00003400 langid = msi_get_property_int( package, szProductLanguage, 0 );
James Hawkinsd52f48f2008-03-06 16:12:40 -06003401 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_LANGUAGEW, langid );
3402
3403 packname = strrchrW( package->PackagePath, '\\' ) + 1;
3404 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGENAMEW, packname );
3405
3406 /* FIXME */
3407 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0 );
3408 msi_reg_set_val_dword( props, INSTALLPROPERTY_INSTANCETYPEW, 0 );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003409
Mike McCormack062ad502005-09-15 15:04:08 +00003410 buffer = msi_dup_property( package, szARPProductIcon );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003411 if (buffer)
3412 {
Mike McCormack75658d72005-09-22 10:33:57 +00003413 LPWSTR path = build_icon_path(package,buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003414 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
Mike McCormack75658d72005-09-22 10:33:57 +00003415 msi_free( path );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003416 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003417 msi_free(buffer);
Aric Stewartc28bb542005-06-09 15:49:11 +00003418
Mike McCormack062ad502005-09-15 15:04:08 +00003419 buffer = msi_dup_property( package, szProductVersion );
Aric Stewartc28bb542005-06-09 15:49:11 +00003420 if (buffer)
3421 {
Mike McCormack230af9d2006-07-14 15:19:08 +09003422 DWORD verdword = msi_version_str_to_dword(buffer);
James Hawkinsd52f48f2008-03-06 16:12:40 -06003423 msi_reg_set_val_dword( hukey, INSTALLPROPERTY_VERSIONW, verdword );
Aric Stewartc28bb542005-06-09 15:49:11 +00003424 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003425 msi_free(buffer);
James Hawkins3de00142008-02-21 00:02:46 -06003426
3427 buffer = strrchrW( package->PackagePath, '\\') + 1;
3428 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05003429 package->Context, MSICODE_PRODUCT,
James Hawkins3de00142008-02-21 00:02:46 -06003430 INSTALLPROPERTY_PACKAGENAMEW, buffer );
3431 if (rc != ERROR_SUCCESS)
3432 goto end;
3433
3434 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05003435 package->Context, MSICODE_PRODUCT,
James Hawkins3de00142008-02-21 00:02:46 -06003436 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty );
3437 if (rc != ERROR_SUCCESS)
3438 goto end;
3439
3440 rc = MsiSourceListSetInfoW( package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05003441 package->Context, MSICODE_PRODUCT,
James Hawkins3de00142008-02-21 00:02:46 -06003442 INSTALLPROPERTY_DISKPROMPTW, szEmpty );
3443 if (rc != ERROR_SUCCESS)
3444 goto end;
3445
Mike McCormackb7270b82005-12-31 13:18:11 +01003446 /* FIXME: Need to write more keys to the user registry */
Aric Stewart68b07492005-01-25 11:05:37 +00003447
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003448 hDb= alloc_msihandle( &package->db->hdr );
Dan Kegel337e1e22006-08-28 09:44:35 -07003449 if (!hDb) {
3450 rc = ERROR_NOT_ENOUGH_MEMORY;
3451 goto end;
3452 }
Aric Stewart68b07492005-01-25 11:05:37 +00003453 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003454 MsiCloseHandle(hDb);
Aric Stewart68b07492005-01-25 11:05:37 +00003455 if (rc == ERROR_SUCCESS)
3456 {
3457 WCHAR guidbuffer[0x200];
3458 size = 0x200;
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003459 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
Aric Stewart68b07492005-01-25 11:05:37 +00003460 guidbuffer, &size);
3461 if (rc == ERROR_SUCCESS)
3462 {
Aric Stewart68b07492005-01-25 11:05:37 +00003463 /* for now we only care about the first guid */
3464 LPWSTR ptr = strchrW(guidbuffer,';');
3465 if (ptr) *ptr = 0;
James Hawkinsd52f48f2008-03-06 16:12:40 -06003466 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, guidbuffer );
Aric Stewart68b07492005-01-25 11:05:37 +00003467 }
3468 else
3469 {
Francois Gouget0edbaf72005-11-10 12:14:56 +00003470 ERR("Unable to query Revision_Number...\n");
Aric Stewart68b07492005-01-25 11:05:37 +00003471 rc = ERROR_SUCCESS;
3472 }
3473 MsiCloseHandle(hSumInfo);
3474 }
3475 else
3476 {
3477 ERR("Unable to open Summary Information\n");
3478 rc = ERROR_SUCCESS;
3479 }
Aric Stewart2cae30b2005-01-19 19:07:40 +00003480
James Hawkins5e46fc92007-07-02 20:20:20 -07003481 /* publish the SourceList info */
3482 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3483 {
James Hawkinscf84e2d2008-02-26 01:55:01 -06003484 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3485 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3486 info->options, info->value);
3487 else
3488 MsiSourceListSetInfoW(package->ProductCode, NULL,
3489 info->context, info->options,
3490 info->property, info->value);
James Hawkins5e46fc92007-07-02 20:20:20 -07003491 }
3492
3493 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3494 {
3495 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3496 disk->context, disk->options,
3497 disk->disk_id, disk->volume_label, disk->disk_prompt);
3498 }
3499
Aric Stewart6269f002005-01-17 13:40:39 +00003500end:
Aric Stewart6269f002005-01-17 13:40:39 +00003501 RegCloseKey(hkey);
Aric Stewart6269f002005-01-17 13:40:39 +00003502 RegCloseKey(hukey);
James Hawkinsc18b7752007-06-26 19:22:46 -07003503 RegCloseKey(hudkey);
3504 RegCloseKey(props);
Aric Stewart6269f002005-01-17 13:40:39 +00003505
Aric Stewart2cf222f2004-07-06 19:00:23 +00003506 return rc;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003507}
3508
Aric Stewartaded32f2005-06-23 09:46:31 +00003509static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3510{
3511 MSIPACKAGE *package = (MSIPACKAGE*)param;
3512 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3513 LPWSTR deformated_section, deformated_key, deformated_value;
3514 LPWSTR folder, fullname = NULL;
3515 MSIRECORD * uirow;
Mike McCormack38d67a42005-08-22 09:15:23 +00003516 INT action;
3517 MSICOMPONENT *comp;
Aric Stewartaded32f2005-06-23 09:46:31 +00003518 static const WCHAR szWindowsFolder[] =
3519 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3520
3521 component = MSI_RecordGetString(row, 8);
Mike McCormack38d67a42005-08-22 09:15:23 +00003522 comp = get_loaded_component(package,component);
Aric Stewartaded32f2005-06-23 09:46:31 +00003523
Mike McCormackd693f462005-10-29 11:36:48 +00003524 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewartaded32f2005-06-23 09:46:31 +00003525 {
3526 TRACE("Skipping ini file due to disabled component %s\n",
3527 debugstr_w(component));
3528
Mike McCormack38d67a42005-08-22 09:15:23 +00003529 comp->Action = comp->Installed;
Aric Stewartaded32f2005-06-23 09:46:31 +00003530
3531 return ERROR_SUCCESS;
3532 }
3533
Mike McCormack38d67a42005-08-22 09:15:23 +00003534 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewartaded32f2005-06-23 09:46:31 +00003535
3536 identifier = MSI_RecordGetString(row,1);
3537 filename = MSI_RecordGetString(row,2);
3538 dirproperty = MSI_RecordGetString(row,3);
3539 section = MSI_RecordGetString(row,4);
3540 key = MSI_RecordGetString(row,5);
3541 value = MSI_RecordGetString(row,6);
3542 action = MSI_RecordGetInteger(row,7);
3543
3544 deformat_string(package,section,&deformated_section);
3545 deformat_string(package,key,&deformated_key);
3546 deformat_string(package,value,&deformated_value);
3547
3548 if (dirproperty)
3549 {
James Hawkins8cedb212007-03-29 02:38:57 -05003550 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
Aric Stewartaded32f2005-06-23 09:46:31 +00003551 if (!folder)
Mike McCormack062ad502005-09-15 15:04:08 +00003552 folder = msi_dup_property( package, dirproperty );
Aric Stewartaded32f2005-06-23 09:46:31 +00003553 }
3554 else
Mike McCormack062ad502005-09-15 15:04:08 +00003555 folder = msi_dup_property( package, szWindowsFolder );
Aric Stewartaded32f2005-06-23 09:46:31 +00003556
3557 if (!folder)
3558 {
3559 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3560 goto cleanup;
3561 }
3562
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003563 fullname = build_directory_name(2, folder, filename);
Aric Stewartaded32f2005-06-23 09:46:31 +00003564
3565 if (action == 0)
3566 {
3567 TRACE("Adding value %s to section %s in %s\n",
3568 debugstr_w(deformated_key), debugstr_w(deformated_section),
3569 debugstr_w(fullname));
3570 WritePrivateProfileStringW(deformated_section, deformated_key,
3571 deformated_value, fullname);
3572 }
3573 else if (action == 1)
3574 {
3575 WCHAR returned[10];
3576 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3577 returned, 10, fullname);
3578 if (returned[0] == 0)
3579 {
3580 TRACE("Adding value %s to section %s in %s\n",
3581 debugstr_w(deformated_key), debugstr_w(deformated_section),
3582 debugstr_w(fullname));
3583
3584 WritePrivateProfileStringW(deformated_section, deformated_key,
3585 deformated_value, fullname);
3586 }
3587 }
3588 else if (action == 3)
3589 FIXME("Append to existing section not yet implemented\n");
3590
3591 uirow = MSI_CreateRecord(4);
3592 MSI_RecordSetStringW(uirow,1,identifier);
3593 MSI_RecordSetStringW(uirow,2,deformated_section);
3594 MSI_RecordSetStringW(uirow,3,deformated_key);
3595 MSI_RecordSetStringW(uirow,4,deformated_value);
3596 ui_actiondata(package,szWriteIniValues,uirow);
3597 msiobj_release( &uirow->hdr );
3598cleanup:
Mike McCormackee034ba2005-09-20 11:59:14 +00003599 msi_free(fullname);
3600 msi_free(folder);
3601 msi_free(deformated_key);
3602 msi_free(deformated_value);
3603 msi_free(deformated_section);
Aric Stewartaded32f2005-06-23 09:46:31 +00003604 return ERROR_SUCCESS;
3605}
3606
Aric Stewart516a9c72005-01-14 15:59:26 +00003607static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3608{
3609 UINT rc;
3610 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003611 static const WCHAR ExecSeqQuery[] =
3612 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003613 '`','I','n','i','F','i','l','e','`',0};
Aric Stewart516a9c72005-01-14 15:59:26 +00003614
3615 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3616 if (rc != ERROR_SUCCESS)
3617 {
3618 TRACE("no IniFile table\n");
3619 return ERROR_SUCCESS;
3620 }
3621
Aric Stewartaded32f2005-06-23 09:46:31 +00003622 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
Aric Stewart516a9c72005-01-14 15:59:26 +00003623 msiobj_release(&view->hdr);
3624 return rc;
3625}
3626
Aric Stewart854bfc42005-06-24 11:33:02 +00003627static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
Aric Stewart6269f002005-01-17 13:40:39 +00003628{
Aric Stewart854bfc42005-06-24 11:33:02 +00003629 MSIPACKAGE *package = (MSIPACKAGE*)param;
3630 LPCWSTR filename;
3631 LPWSTR FullName;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003632 MSIFILE *file;
Aric Stewart854bfc42005-06-24 11:33:02 +00003633 DWORD len;
Aric Stewart8e233e92005-03-01 11:45:19 +00003634 static const WCHAR ExeStr[] =
Aric Stewartc5a14432005-05-18 17:46:12 +00003635 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3636 static const WCHAR close[] = {'\"',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00003637 STARTUPINFOW si;
3638 PROCESS_INFORMATION info;
3639 BOOL brc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003640 MSIRECORD *uirow;
3641 LPWSTR uipath, p;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003642
3643 memset(&si,0,sizeof(STARTUPINFOW));
3644
Aric Stewart854bfc42005-06-24 11:33:02 +00003645 filename = MSI_RecordGetString(row,1);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003646 file = get_loaded_file( package, filename );
Aric Stewart854bfc42005-06-24 11:33:02 +00003647
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003648 if (!file)
Aric Stewart854bfc42005-06-24 11:33:02 +00003649 {
3650 ERR("Unable to find file id %s\n",debugstr_w(filename));
3651 return ERROR_SUCCESS;
3652 }
3653
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003654 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
Aric Stewart854bfc42005-06-24 11:33:02 +00003655
Mike McCormackee034ba2005-09-20 11:59:14 +00003656 FullName = msi_alloc(len*sizeof(WCHAR));
Aric Stewart854bfc42005-06-24 11:33:02 +00003657 strcpyW(FullName,ExeStr);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003658 strcatW( FullName, file->TargetPath );
Aric Stewart854bfc42005-06-24 11:33:02 +00003659 strcatW(FullName,close);
3660
3661 TRACE("Registering %s\n",debugstr_w(FullName));
3662 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3663 &si, &info);
3664
3665 if (brc)
3666 msi_dialog_check_messages(info.hProcess);
3667
Mike McCormackee034ba2005-09-20 11:59:14 +00003668 msi_free(FullName);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003669
3670 /* the UI chunk */
3671 uirow = MSI_CreateRecord( 2 );
3672 uipath = strdupW( file->TargetPath );
3673 p = strrchrW(uipath,'\\');
3674 if (p)
Rob Shearman220f93d2007-04-24 12:33:56 +01003675 p[0]=0;
3676 MSI_RecordSetStringW( uirow, 1, &p[1] );
Robert Shearmand2e48e02006-01-23 17:29:50 +01003677 MSI_RecordSetStringW( uirow, 2, uipath);
3678 ui_actiondata( package, szSelfRegModules, uirow);
3679 msiobj_release( &uirow->hdr );
3680 msi_free( uipath );
3681 /* FIXME: call ui_progress? */
3682
Aric Stewart854bfc42005-06-24 11:33:02 +00003683 return ERROR_SUCCESS;
3684}
3685
3686static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3687{
3688 UINT rc;
3689 MSIQUERY * view;
3690 static const WCHAR ExecSeqQuery[] =
3691 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3692 '`','S','e','l','f','R','e','g','`',0};
3693
Aric Stewart6269f002005-01-17 13:40:39 +00003694 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3695 if (rc != ERROR_SUCCESS)
3696 {
3697 TRACE("no SelfReg table\n");
3698 return ERROR_SUCCESS;
3699 }
3700
Aric Stewart854bfc42005-06-24 11:33:02 +00003701 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
Aric Stewart6269f002005-01-17 13:40:39 +00003702 msiobj_release(&view->hdr);
Aric Stewart854bfc42005-06-24 11:33:02 +00003703
3704 return ERROR_SUCCESS;
Aric Stewart6269f002005-01-17 13:40:39 +00003705}
3706
3707static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3708{
Mike McCormack1da28582005-08-22 14:09:17 +00003709 MSIFEATURE *feature;
Aric Stewart6269f002005-01-17 13:40:39 +00003710 UINT rc;
Aric Stewart68b07492005-01-25 11:05:37 +00003711 HKEY hkey=0;
3712 HKEY hukey=0;
James Hawkins9f11a5a2007-11-01 03:13:28 -05003713 HKEY userdata=0;
James Hawkins6ac08162007-08-09 11:38:48 -07003714
3715 if (!msi_check_publish(package))
3716 return ERROR_SUCCESS;
3717
Aric Stewartadaef112005-07-07 20:27:06 +00003718 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003719 if (rc != ERROR_SUCCESS)
3720 goto end;
3721
Aric Stewartadaef112005-07-07 20:27:06 +00003722 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003723 if (rc != ERROR_SUCCESS)
3724 goto end;
3725
James Hawkins9f11a5a2007-11-01 03:13:28 -05003726 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &userdata, TRUE);
3727 if (rc != ERROR_SUCCESS)
3728 goto end;
3729
Aric Stewart6269f002005-01-17 13:40:39 +00003730 /* here the guids are base 85 encoded */
Mike McCormack1da28582005-08-22 14:09:17 +00003731 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00003732 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003733 ComponentList *cl;
Aric Stewart6269f002005-01-17 13:40:39 +00003734 LPWSTR data = NULL;
3735 GUID clsid;
Aric Stewart6269f002005-01-17 13:40:39 +00003736 INT size;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003737 BOOL absent = FALSE;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003738 MSIRECORD *uirow;
Aric Stewart6269f002005-01-17 13:40:39 +00003739
Mike McCormack1da28582005-08-22 14:09:17 +00003740 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3741 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3742 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003743 absent = TRUE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003744
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003745 size = 1;
Mike McCormack1da28582005-08-22 14:09:17 +00003746 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003747 {
3748 size += 21;
3749 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00003750 if (feature->Feature_Parent)
Mike McCormack1da28582005-08-22 14:09:17 +00003751 size += strlenW( feature->Feature_Parent )+2;
Aric Stewart6269f002005-01-17 13:40:39 +00003752
Mike McCormackee034ba2005-09-20 11:59:14 +00003753 data = msi_alloc(size * sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00003754
3755 data[0] = 0;
Mike McCormack1da28582005-08-22 14:09:17 +00003756 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00003757 {
Mike McCormack38d67a42005-08-22 09:15:23 +00003758 MSICOMPONENT* component = cl->component;
Aric Stewart6269f002005-01-17 13:40:39 +00003759 WCHAR buf[21];
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003760
Mike McCormack3a940112006-04-19 02:29:03 +09003761 buf[0] = 0;
Mike McCormackefcc1ec2005-09-12 12:07:15 +00003762 if (component->ComponentId)
Aric Stewartc5a14432005-05-18 17:46:12 +00003763 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003764 TRACE("From %s\n",debugstr_w(component->ComponentId));
3765 CLSIDFromString(component->ComponentId, &clsid);
Aric Stewartc5a14432005-05-18 17:46:12 +00003766 encode_base85_guid(&clsid,buf);
3767 TRACE("to %s\n",debugstr_w(buf));
3768 strcatW(data,buf);
3769 }
Aric Stewart6269f002005-01-17 13:40:39 +00003770 }
James Hawkins9f11a5a2007-11-01 03:13:28 -05003771
Mike McCormack79ca56c2005-09-13 10:37:37 +00003772 if (feature->Feature_Parent)
Aric Stewart6269f002005-01-17 13:40:39 +00003773 {
3774 static const WCHAR sep[] = {'\2',0};
3775 strcatW(data,sep);
Mike McCormack1da28582005-08-22 14:09:17 +00003776 strcatW(data,feature->Feature_Parent);
Aric Stewart6269f002005-01-17 13:40:39 +00003777 }
3778
Mike McCormack4db02cd2005-09-15 14:58:38 +00003779 msi_reg_set_val_str( hkey, feature->Feature, data );
James Hawkins9f11a5a2007-11-01 03:13:28 -05003780 msi_reg_set_val_str( userdata, feature->Feature, data );
Mike McCormackee034ba2005-09-20 11:59:14 +00003781 msi_free(data);
Aric Stewart6269f002005-01-17 13:40:39 +00003782
Mike McCormack79ca56c2005-09-13 10:37:37 +00003783 size = 0;
3784 if (feature->Feature_Parent)
3785 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003786 if (!absent)
3787 {
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02003788 static const WCHAR emptyW[] = {0};
3789 size += sizeof(WCHAR);
Mike McCormack1da28582005-08-22 14:09:17 +00003790 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02003791 (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : emptyW),size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003792 }
3793 else
3794 {
Mike McCormack79ca56c2005-09-13 10:37:37 +00003795 size += 2*sizeof(WCHAR);
Mike McCormackee034ba2005-09-20 11:59:14 +00003796 data = msi_alloc(size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003797 data[0] = 0x6;
Mike McCormack79ca56c2005-09-13 10:37:37 +00003798 data[1] = 0;
3799 if (feature->Feature_Parent)
3800 strcpyW( &data[1], feature->Feature_Parent );
Mike McCormack1da28582005-08-22 14:09:17 +00003801 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
Mike McCormack16466af2005-07-06 10:33:30 +00003802 (LPBYTE)data,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00003803 msi_free(data);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003804 }
Robert Shearmand2e48e02006-01-23 17:29:50 +01003805
3806 /* the UI chunk */
3807 uirow = MSI_CreateRecord( 1 );
3808 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3809 ui_actiondata( package, szPublishFeatures, uirow);
3810 msiobj_release( &uirow->hdr );
3811 /* FIXME: call ui_progress? */
Aric Stewart6269f002005-01-17 13:40:39 +00003812 }
3813
Aric Stewart6269f002005-01-17 13:40:39 +00003814end:
Aric Stewart6269f002005-01-17 13:40:39 +00003815 RegCloseKey(hkey);
3816 RegCloseKey(hukey);
3817 return rc;
3818}
3819
James Hawkins6ac08162007-08-09 11:38:48 -07003820static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3821{
3822 UINT r;
3823 HKEY hkey;
3824
3825 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3826
3827 r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
3828 if (r == ERROR_SUCCESS)
3829 {
3830 RegDeleteValueW(hkey, feature->Feature);
3831 RegCloseKey(hkey);
3832 }
3833
3834 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
3835 if (r == ERROR_SUCCESS)
3836 {
3837 RegDeleteValueW(hkey, feature->Feature);
3838 RegCloseKey(hkey);
3839 }
3840
3841 return ERROR_SUCCESS;
3842}
3843
James Hawkinsccdf5782007-11-01 03:14:18 -05003844static BOOL msi_check_unpublish(MSIPACKAGE *package)
3845{
3846 MSIFEATURE *feature;
3847
3848 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3849 {
3850 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3851 return FALSE;
3852 }
3853
3854 return TRUE;
3855}
3856
James Hawkins6ac08162007-08-09 11:38:48 -07003857static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3858{
3859 MSIFEATURE *feature;
3860
James Hawkinsccdf5782007-11-01 03:14:18 -05003861 if (!msi_check_unpublish(package))
James Hawkins6ac08162007-08-09 11:38:48 -07003862 return ERROR_SUCCESS;
3863
3864 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3865 {
3866 msi_unpublish_feature(package, feature);
3867 }
3868
3869 return ERROR_SUCCESS;
3870}
3871
Mike McCormack5f830692006-09-08 16:20:46 +09003872static UINT msi_get_local_package_name( LPWSTR path )
Mike McCormack61f24a42005-09-30 10:32:41 +00003873{
Mike McCormack5f830692006-09-08 16:20:46 +09003874 static const WCHAR szInstaller[] = {
3875 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3876 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3877 DWORD time, len, i;
3878 HANDLE handle;
Mike McCormack61f24a42005-09-30 10:32:41 +00003879
Mike McCormack5f830692006-09-08 16:20:46 +09003880 time = GetTickCount();
3881 GetWindowsDirectoryW( path, MAX_PATH );
3882 lstrcatW( path, szInstaller );
3883 CreateDirectoryW( path, NULL );
3884
3885 len = lstrlenW(path);
3886 for (i=0; i<0x10000; i++)
Mike McCormack61f24a42005-09-30 10:32:41 +00003887 {
Mike McCormack5f830692006-09-08 16:20:46 +09003888 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3889 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3890 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
Mike McCormack61f24a42005-09-30 10:32:41 +00003891 if (handle != INVALID_HANDLE_VALUE)
3892 {
3893 CloseHandle(handle);
3894 break;
3895 }
3896 if (GetLastError() != ERROR_FILE_EXISTS &&
3897 GetLastError() != ERROR_SHARING_VIOLATION)
Mike McCormack5f830692006-09-08 16:20:46 +09003898 return ERROR_FUNCTION_FAILED;
3899 }
Mike McCormack61f24a42005-09-30 10:32:41 +00003900
Mike McCormack5f830692006-09-08 16:20:46 +09003901 return ERROR_SUCCESS;
3902}
3903
3904static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3905{
Mike McCormack5f830692006-09-08 16:20:46 +09003906 WCHAR packagefile[MAX_PATH];
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05003907 HKEY props;
Mike McCormack5f830692006-09-08 16:20:46 +09003908 UINT r;
3909
3910 r = msi_get_local_package_name( packagefile );
3911 if (r != ERROR_SUCCESS)
3912 return r;
Mike McCormack61f24a42005-09-30 10:32:41 +00003913
3914 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3915
James Hawkinsc37849a2008-01-05 13:50:59 -07003916 r = CopyFileW( package->db->path, packagefile, FALSE);
Mike McCormack61f24a42005-09-30 10:32:41 +00003917
3918 if (!r)
3919 {
Mike McCormackf1d46462006-10-05 13:41:22 +09003920 ERR("Unable to copy package (%s -> %s) (error %d)\n",
James Hawkinsc37849a2008-01-05 13:50:59 -07003921 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
Mike McCormack61f24a42005-09-30 10:32:41 +00003922 return ERROR_FUNCTION_FAILED;
3923 }
3924
Mike McCormack61f24a42005-09-30 10:32:41 +00003925 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05003926
James Hawkinse21a26e2008-04-05 05:41:54 -05003927 r = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05003928 if (r != ERROR_SUCCESS)
3929 return r;
3930
3931 msi_reg_set_val_str(props, INSTALLPROPERTY_LOCALPACKAGEW, packagefile);
3932 RegCloseKey(props);
Mike McCormack61f24a42005-09-30 10:32:41 +00003933 return ERROR_SUCCESS;
3934}
3935
Mike McCormackba293ee2005-10-27 12:08:16 +00003936static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3937{
3938 LPWSTR prop, val, key;
3939 static const LPCSTR propval[] = {
3940 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3941 "ARPCONTACT", "Contact",
3942 "ARPCOMMENTS", "Comments",
3943 "ProductName", "DisplayName",
3944 "ProductVersion", "DisplayVersion",
3945 "ARPHELPLINK", "HelpLink",
3946 "ARPHELPTELEPHONE", "HelpTelephone",
3947 "ARPINSTALLLOCATION", "InstallLocation",
3948 "SourceDir", "InstallSource",
3949 "Manufacturer", "Publisher",
3950 "ARPREADME", "Readme",
3951 "ARPSIZE", "Size",
3952 "ARPURLINFOABOUT", "URLInfoAbout",
3953 "ARPURLUPDATEINFO", "URLUpdateInfo",
3954 NULL,
3955 };
3956 const LPCSTR *p = propval;
3957
3958 while( *p )
3959 {
3960 prop = strdupAtoW( *p++ );
3961 key = strdupAtoW( *p++ );
3962 val = msi_dup_property( package, prop );
3963 msi_reg_set_val_str( hkey, key, val );
3964 msi_free(val);
3965 msi_free(key);
3966 msi_free(prop);
3967 }
3968 return ERROR_SUCCESS;
3969}
3970
Aric Stewart2cae30b2005-01-19 19:07:40 +00003971static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3972{
Aric Stewart68b07492005-01-25 11:05:37 +00003973 HKEY hkey=0;
James Hawkins0e44e092007-07-02 20:21:58 -07003974 HKEY hudkey=0, props=0;
Aric Stewarte9db87b2005-06-17 21:25:41 +00003975 LPWSTR buffer = NULL;
Mike McCormackba293ee2005-10-27 12:08:16 +00003976 UINT rc;
Mike McCormack74f0de92005-09-29 10:32:39 +00003977 DWORD size, langid;
Mike McCormack4db02cd2005-09-15 14:58:38 +00003978 static const WCHAR szWindowsInstaller[] =
Mike McCormackba293ee2005-10-27 12:08:16 +00003979 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
Aric Stewart36a01502005-06-08 19:07:52 +00003980 static const WCHAR szUpgradeCode[] =
3981 {'U','p','g','r','a','d','e','C','o','d','e',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003982 static const WCHAR modpath_fmt[] =
Mike McCormackba293ee2005-10-27 12:08:16 +00003983 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3984 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003985 static const WCHAR szModifyPath[] =
3986 {'M','o','d','i','f','y','P','a','t','h',0};
3987 static const WCHAR szUninstallString[] =
3988 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3989 static const WCHAR szEstimatedSize[] =
3990 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003991 static const WCHAR szProductLanguage[] =
3992 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3993 static const WCHAR szProductVersion[] =
3994 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
James Hawkinsd52f48f2008-03-06 16:12:40 -06003995 static const WCHAR szProductName[] =
3996 {'P','r','o','d','u','c','t','N','a','m','e',0};
3997 static const WCHAR szDisplayName[] =
3998 {'D','i','s','p','l','a','y','N','a','m','e',0};
3999 static const WCHAR szDisplayVersion[] =
4000 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4001 static const WCHAR szManufacturer[] =
4002 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00004003
4004 SYSTEMTIME systime;
James Hawkins837588c2008-01-06 12:23:38 -07004005 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
Aric Stewart36a01502005-06-08 19:07:52 +00004006 LPWSTR upgrade_code;
James Hawkins0e44e092007-07-02 20:21:58 -07004007 WCHAR szDate[9];
4008
4009 /* FIXME: also need to publish if the product is in advertise mode */
4010 if (!msi_check_publish(package))
4011 return ERROR_SUCCESS;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004012
Aric Stewartadaef112005-07-07 20:27:06 +00004013 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004014 if (rc != ERROR_SUCCESS)
Mike McCormackba293ee2005-10-27 12:08:16 +00004015 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004016
James Hawkinsbcba82d2008-04-05 06:02:04 -05004017 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4018 {
4019 rc = MSIREG_OpenLocalSystemInstallProps(package->ProductCode, &props, TRUE);
4020 if (rc != ERROR_SUCCESS)
4021 return rc;
4022 }
4023 else
4024 {
4025 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &props, TRUE);
4026 if (rc != ERROR_SUCCESS)
4027 return rc;
4028 }
James Hawkinsd52f48f2008-03-06 16:12:40 -06004029
Aric Stewart2cae30b2005-01-19 19:07:40 +00004030 /* dump all the info i can grab */
Mike McCormackb7270b82005-12-31 13:18:11 +01004031 /* FIXME: Flesh out more information */
Aric Stewart2cae30b2005-01-19 19:07:40 +00004032
Mike McCormackba293ee2005-10-27 12:08:16 +00004033 msi_write_uninstall_property_vals( package, hkey );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004034
Mike McCormack4db02cd2005-09-15 14:58:38 +00004035 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004036
Mike McCormack61f24a42005-09-30 10:32:41 +00004037 msi_make_package_local( package, hkey );
Aric Stewart36a01502005-06-08 19:07:52 +00004038
Aric Stewarte9db87b2005-06-17 21:25:41 +00004039 /* do ModifyPath and UninstallString */
4040 size = deformat_string(package,modpath_fmt,&buffer);
Mike McCormack16466af2005-07-06 10:33:30 +00004041 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
4042 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00004043 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00004044
Mike McCormackb7270b82005-12-31 13:18:11 +01004045 /* FIXME: Write real Estimated Size when we have it */
Mike McCormack4db02cd2005-09-15 14:58:38 +00004046 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
James Hawkinsd52f48f2008-03-06 16:12:40 -06004047
4048 buffer = msi_dup_property( package, szProductName );
4049 msi_reg_set_val_str( props, szDisplayName, buffer );
4050 msi_free(buffer);
4051
4052 buffer = msi_dup_property( package, cszSourceDir );
4053 msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
4054 msi_free(buffer);
4055
4056 buffer = msi_dup_property( package, szManufacturer );
4057 msi_reg_set_val_str( props, INSTALLPROPERTY_PUBLISHERW, buffer);
4058 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00004059
4060 GetLocalTime(&systime);
Mike McCormackba293ee2005-10-27 12:08:16 +00004061 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
4062 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
James Hawkinsd52f48f2008-03-06 16:12:40 -06004063 msi_reg_set_val_str( props, INSTALLPROPERTY_INSTALLDATEW, szDate );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004064
Mike McCormack74f0de92005-09-29 10:32:39 +00004065 langid = msi_get_property_int( package, szProductLanguage, 0 );
4066 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004067
Mike McCormack062ad502005-09-15 15:04:08 +00004068 buffer = msi_dup_property( package, szProductVersion );
James Hawkinsd52f48f2008-03-06 16:12:40 -06004069 msi_reg_set_val_str( props, szDisplayVersion, buffer );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004070 if (buffer)
4071 {
Mike McCormack230af9d2006-07-14 15:19:08 +09004072 DWORD verdword = msi_version_str_to_dword(buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00004073
4074 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
James Hawkinsd52f48f2008-03-06 16:12:40 -06004075 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONW, verdword );
Mike McCormack4db02cd2005-09-15 14:58:38 +00004076 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
James Hawkinsd52f48f2008-03-06 16:12:40 -06004077 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
Mike McCormack4db02cd2005-09-15 14:58:38 +00004078 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
James Hawkinsd52f48f2008-03-06 16:12:40 -06004079 msi_reg_set_val_dword( props, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004080 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004081 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00004082
Aric Stewart36a01502005-06-08 19:07:52 +00004083 /* Handle Upgrade Codes */
Mike McCormack062ad502005-09-15 15:04:08 +00004084 upgrade_code = msi_dup_property( package, szUpgradeCode );
Aric Stewart36a01502005-06-08 19:07:52 +00004085 if (upgrade_code)
4086 {
4087 HKEY hkey2;
4088 WCHAR squashed[33];
4089 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
Aric Stewartadaef112005-07-07 20:27:06 +00004090 squash_guid(package->ProductCode,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00004091 msi_reg_set_val_str( hkey2, squashed, NULL );
Aric Stewart36a01502005-06-08 19:07:52 +00004092 RegCloseKey(hkey2);
4093 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
Aric Stewartadaef112005-07-07 20:27:06 +00004094 squash_guid(package->ProductCode,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00004095 msi_reg_set_val_str( hkey2, squashed, NULL );
Aric Stewart36a01502005-06-08 19:07:52 +00004096 RegCloseKey(hkey2);
4097
Mike McCormackee034ba2005-09-20 11:59:14 +00004098 msi_free(upgrade_code);
Aric Stewart36a01502005-06-08 19:07:52 +00004099 }
James Hawkinsbcba82d2008-04-05 06:02:04 -05004100
Aric Stewart2cae30b2005-01-19 19:07:40 +00004101 RegCloseKey(hkey);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004102
James Hawkins0e44e092007-07-02 20:21:58 -07004103 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
4104 if (rc != ERROR_SUCCESS)
4105 return rc;
4106
4107 RegCloseKey(hudkey);
4108
James Hawkins0e44e092007-07-02 20:21:58 -07004109 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
4110 RegCloseKey(props);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004111
Aric Stewart2cae30b2005-01-19 19:07:40 +00004112 return ERROR_SUCCESS;
4113}
4114
4115static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4116{
Mike McCormacka977b2c2005-11-03 09:56:29 +00004117 return execute_script(package,INSTALL_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004118}
4119
James Hawkins624bbbe2007-07-02 20:20:54 -07004120static UINT msi_unpublish_product(MSIPACKAGE *package)
4121{
4122 LPWSTR remove = NULL;
4123 LPWSTR *features = NULL;
4124 BOOL full_uninstall = TRUE;
4125 MSIFEATURE *feature;
4126
4127 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4128 static const WCHAR szAll[] = {'A','L','L',0};
4129
4130 remove = msi_dup_property(package, szRemove);
4131 if (!remove)
4132 return ERROR_SUCCESS;
4133
4134 features = msi_split_string(remove, ',');
4135 if (!features)
4136 {
4137 msi_free(remove);
4138 ERR("REMOVE feature list is empty!\n");
4139 return ERROR_FUNCTION_FAILED;
4140 }
4141
4142 if (!lstrcmpW(features[0], szAll))
4143 full_uninstall = TRUE;
4144 else
4145 {
4146 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4147 {
4148 if (feature->Action != INSTALLSTATE_ABSENT)
4149 full_uninstall = FALSE;
4150 }
4151 }
4152
4153 if (!full_uninstall)
4154 goto done;
4155
4156 MSIREG_DeleteProductKey(package->ProductCode);
4157 MSIREG_DeleteUserProductKey(package->ProductCode);
4158 MSIREG_DeleteUserDataProductKey(package->ProductCode);
James Hawkins6ac08162007-08-09 11:38:48 -07004159 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
James Hawkinsf6b27672007-11-13 00:47:21 -06004160 MSIREG_DeleteUninstallKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004161
4162done:
4163 msi_free(remove);
4164 msi_free(features);
4165 return ERROR_SUCCESS;
4166}
4167
Aric Stewart2cae30b2005-01-19 19:07:40 +00004168static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4169{
Aric Stewart9cd707d2005-05-27 19:24:22 +00004170 UINT rc;
4171
James Hawkins624bbbe2007-07-02 20:20:54 -07004172 rc = msi_unpublish_product(package);
4173 if (rc != ERROR_SUCCESS)
4174 return rc;
4175
Francois Gouget1ccf9442006-11-12 19:51:37 +01004176 /* turn off scheduling */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004177 package->script->CurrentlyScripting= FALSE;
4178
Aric Stewart54c67dd2005-01-25 20:17:09 +00004179 /* first do the same as an InstallExecute */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004180 rc = ACTION_InstallExecute(package);
4181 if (rc != ERROR_SUCCESS)
4182 return rc;
Aric Stewart54c67dd2005-01-25 20:17:09 +00004183
4184 /* then handle Commit Actions */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004185 rc = execute_script(package,COMMIT_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004186
Aric Stewart9cd707d2005-05-27 19:24:22 +00004187 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004188}
4189
James Hawkinsc2e91582007-05-29 12:03:05 -07004190UINT ACTION_ForceReboot(MSIPACKAGE *package)
Aric Stewart2cae30b2005-01-19 19:07:40 +00004191{
4192 static const WCHAR RunOnce[] = {
4193 'S','o','f','t','w','a','r','e','\\',
4194 'M','i','c','r','o','s','o','f','t','\\',
4195 'W','i','n','d','o','w','s','\\',
4196 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004197 'R','u','n','O','n','c','e',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004198 static const WCHAR InstallRunOnce[] = {
4199 'S','o','f','t','w','a','r','e','\\',
4200 'M','i','c','r','o','s','o','f','t','\\',
4201 'W','i','n','d','o','w','s','\\',
4202 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4203 'I','n','s','t','a','l','l','e','r','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004204 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004205
4206 static const WCHAR msiexec_fmt[] = {
Juan Lang014ad3b2005-03-01 10:41:52 +00004207 '%','s',
Aric Stewart2cae30b2005-01-19 19:07:40 +00004208 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4209 '\"','%','s','\"',0};
4210 static const WCHAR install_fmt[] = {
4211 '/','I',' ','\"','%','s','\"',' ',
4212 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4213 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
Juan Lang014ad3b2005-03-01 10:41:52 +00004214 WCHAR buffer[256], sysdir[MAX_PATH];
Aric Stewartadaef112005-07-07 20:27:06 +00004215 HKEY hkey;
Mike McCormack4db02cd2005-09-15 14:58:38 +00004216 WCHAR squished_pc[100];
Aric Stewart2cae30b2005-01-19 19:07:40 +00004217
Aric Stewartadaef112005-07-07 20:27:06 +00004218 squash_guid(package->ProductCode,squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004219
Juan Lang014ad3b2005-03-01 10:41:52 +00004220 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
Aric Stewart2cae30b2005-01-19 19:07:40 +00004221 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
Juan Lang014ad3b2005-03-01 10:41:52 +00004222 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4223 squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004224
Mike McCormack4db02cd2005-09-15 14:58:38 +00004225 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004226 RegCloseKey(hkey);
4227
4228 TRACE("Reboot command %s\n",debugstr_w(buffer));
4229
4230 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
Aric Stewartadaef112005-07-07 20:27:06 +00004231 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004232
Mike McCormack4db02cd2005-09-15 14:58:38 +00004233 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004234 RegCloseKey(hkey);
4235
Aric Stewart68b07492005-01-25 11:05:37 +00004236 return ERROR_INSTALL_SUSPEND;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004237}
4238
James Hawkins563a50a2006-10-09 00:05:04 -07004239static UINT ACTION_ResolveSource(MSIPACKAGE* package)
Aric Stewart90c57392005-01-31 16:23:12 +00004240{
Mike McCormackb9211182006-11-20 16:27:36 +09004241 DWORD attrib;
Aric Stewart94d68182005-08-15 20:50:06 +00004242 UINT rc;
Mike McCormackfc564232006-11-20 16:17:03 +09004243
Aric Stewart90c57392005-01-31 16:23:12 +00004244 /*
Mike McCormackfc564232006-11-20 16:17:03 +09004245 * We are currently doing what should be done here in the top level Install
4246 * however for Administrative and uninstalls this step will be needed
Aric Stewart90c57392005-01-31 16:23:12 +00004247 */
Aric Stewart94d68182005-08-15 20:50:06 +00004248 if (!package->PackagePath)
4249 return ERROR_SUCCESS;
4250
James Hawkinsc777d302008-01-05 13:45:13 -07004251 msi_set_sourcedir_props(package, TRUE);
James Hawkinsc5075432006-10-10 13:39:50 -07004252
James Hawkinse28cedf2008-01-05 13:48:32 -07004253 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004254 if (attrib == INVALID_FILE_ATTRIBUTES)
4255 {
4256 LPWSTR prompt;
4257 LPWSTR msg;
4258 DWORD size = 0;
4259
4260 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004261 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004262 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4263 if (rc == ERROR_MORE_DATA)
4264 {
Mike McCormackee034ba2005-09-20 11:59:14 +00004265 prompt = msi_alloc(size * sizeof(WCHAR));
Aric Stewart94d68182005-08-15 20:50:06 +00004266 MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004267 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004268 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4269 }
4270 else
James Hawkinse28cedf2008-01-05 13:48:32 -07004271 prompt = strdupW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004272
4273 msg = generate_error_string(package,1302,1,prompt);
4274 while(attrib == INVALID_FILE_ATTRIBUTES)
4275 {
4276 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4277 if (rc == IDCANCEL)
4278 {
4279 rc = ERROR_INSTALL_USEREXIT;
4280 break;
4281 }
James Hawkinse28cedf2008-01-05 13:48:32 -07004282 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004283 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004284 msi_free(prompt);
Aric Stewart94d68182005-08-15 20:50:06 +00004285 rc = ERROR_SUCCESS;
4286 }
4287 else
4288 return ERROR_SUCCESS;
4289
4290 return rc;
Aric Stewart90c57392005-01-31 16:23:12 +00004291}
4292
Aric Stewartc7e88e02005-02-10 17:09:44 +00004293static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4294{
Aric Stewartc7e88e02005-02-10 17:09:44 +00004295 HKEY hkey=0;
4296 LPWSTR buffer;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004297 LPWSTR productid;
4298 UINT rc,i;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004299
4300 static const WCHAR szPropKeys[][80] =
4301 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004302 {'P','r','o','d','u','c','t','I','D',0},
4303 {'U','S','E','R','N','A','M','E',0},
4304 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4305 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004306 };
4307
4308 static const WCHAR szRegKeys[][80] =
4309 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004310 {'P','r','o','d','u','c','t','I','D',0},
4311 {'R','e','g','O','w','n','e','r',0},
4312 {'R','e','g','C','o','m','p','a','n','y',0},
4313 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004314 };
4315
James Hawkinsd52f48f2008-03-06 16:12:40 -06004316 if (msi_check_unpublish(package))
4317 {
4318 MSIREG_DeleteUserDataProductKey(package->ProductCode);
4319 return ERROR_SUCCESS;
4320 }
4321
Mike McCormack062ad502005-09-15 15:04:08 +00004322 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004323 if (!productid)
4324 return ERROR_SUCCESS;
4325
James Hawkinse21a26e2008-04-05 05:41:54 -05004326 rc = MSIREG_OpenCurrentUserInstallProps(package->ProductCode, &hkey, TRUE);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004327 if (rc != ERROR_SUCCESS)
4328 goto end;
4329
Mike McCormack67189f92005-09-16 18:45:19 +00004330 for( i = 0; szPropKeys[i][0]; i++ )
Aric Stewartc7e88e02005-02-10 17:09:44 +00004331 {
Mike McCormack062ad502005-09-15 15:04:08 +00004332 buffer = msi_dup_property( package, szPropKeys[i] );
Mike McCormack4db02cd2005-09-15 14:58:38 +00004333 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00004334 msi_free( buffer );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004335 }
4336
4337end:
Mike McCormackee034ba2005-09-20 11:59:14 +00004338 msi_free(productid);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004339 RegCloseKey(hkey);
4340
Robert Shearmand2e48e02006-01-23 17:29:50 +01004341 /* FIXME: call ui_actiondata */
4342
James Hawkinsd52f48f2008-03-06 16:12:40 -06004343 return rc;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004344}
4345
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004346
4347static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4348{
4349 UINT rc;
Aric Stewart25f1e752005-06-24 12:14:52 +00004350
Aric Stewartc9802932005-06-30 20:45:43 +00004351 package->script->InWhatSequence |= SEQUENCE_EXEC;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004352 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004353 return rc;
4354}
4355
Aric Stewart0af24872005-02-25 14:00:09 +00004356
Aric Stewart072c5e52005-04-20 12:50:05 +00004357static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4358{
4359 MSIPACKAGE *package = (MSIPACKAGE*)param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00004360 LPCWSTR compgroupid=NULL;
4361 LPCWSTR feature=NULL;
4362 LPCWSTR text = NULL;
4363 LPCWSTR qualifier = NULL;
4364 LPCWSTR component = NULL;
Aric Stewart6f43c182005-05-26 12:24:28 +00004365 LPWSTR advertise = NULL;
4366 LPWSTR output = NULL;
Aric Stewart072c5e52005-04-20 12:50:05 +00004367 HKEY hkey;
4368 UINT rc = ERROR_SUCCESS;
Mike McCormack38d67a42005-08-22 09:15:23 +00004369 MSICOMPONENT *comp;
Aric Stewart072c5e52005-04-20 12:50:05 +00004370 DWORD sz = 0;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004371 MSIRECORD *uirow;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004372
Aric Stewart09b0aba2005-06-09 20:30:59 +00004373 component = MSI_RecordGetString(rec,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00004374 comp = get_loaded_component(package,component);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004375
Mike McCormackd693f462005-10-29 11:36:48 +00004376 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4377 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4378 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004379 {
4380 TRACE("Skipping: Component %s not scheduled for install\n",
4381 debugstr_w(component));
Aric Stewart6f43c182005-05-26 12:24:28 +00004382
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004383 return ERROR_SUCCESS;
4384 }
Aric Stewart072c5e52005-04-20 12:50:05 +00004385
Aric Stewart09b0aba2005-06-09 20:30:59 +00004386 compgroupid = MSI_RecordGetString(rec,1);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004387 qualifier = MSI_RecordGetString(rec,2);
Aric Stewart072c5e52005-04-20 12:50:05 +00004388
4389 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4390 if (rc != ERROR_SUCCESS)
4391 goto end;
4392
Aric Stewart09b0aba2005-06-09 20:30:59 +00004393 text = MSI_RecordGetString(rec,4);
Aric Stewart09b0aba2005-06-09 20:30:59 +00004394 feature = MSI_RecordGetString(rec,5);
Aric Stewart072c5e52005-04-20 12:50:05 +00004395
Mike McCormack38d67a42005-08-22 09:15:23 +00004396 advertise = create_component_advertise_string(package, comp, feature);
Aric Stewart072c5e52005-04-20 12:50:05 +00004397
Aric Stewart6f43c182005-05-26 12:24:28 +00004398 sz = strlenW(advertise);
4399
Aric Stewart072c5e52005-04-20 12:50:05 +00004400 if (text)
4401 sz += lstrlenW(text);
Aric Stewart072c5e52005-04-20 12:50:05 +00004402
4403 sz+=3;
4404 sz *= sizeof(WCHAR);
4405
Mike McCormack3a940112006-04-19 02:29:03 +09004406 output = msi_alloc_zero(sz);
Aric Stewart6f43c182005-05-26 12:24:28 +00004407 strcpyW(output,advertise);
Mike McCormack470f23d2005-09-22 10:56:26 +00004408 msi_free(advertise);
Aric Stewart072c5e52005-04-20 12:50:05 +00004409
4410 if (text)
4411 strcatW(output,text);
4412
Mike McCormack4db02cd2005-09-15 14:58:38 +00004413 msi_reg_set_val_multi_str( hkey, qualifier, output );
Aric Stewart072c5e52005-04-20 12:50:05 +00004414
4415end:
4416 RegCloseKey(hkey);
Mike McCormackee034ba2005-09-20 11:59:14 +00004417 msi_free(output);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004418
4419 /* the UI chunk */
4420 uirow = MSI_CreateRecord( 2 );
4421 MSI_RecordSetStringW( uirow, 1, compgroupid );
4422 MSI_RecordSetStringW( uirow, 2, qualifier);
4423 ui_actiondata( package, szPublishComponents, uirow);
4424 msiobj_release( &uirow->hdr );
4425 /* FIXME: call ui_progress? */
4426
Aric Stewart072c5e52005-04-20 12:50:05 +00004427 return rc;
4428}
4429
4430/*
4431 * At present I am ignorning the advertised components part of this and only
4432 * focusing on the qualified component sets
4433 */
4434static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4435{
4436 UINT rc;
4437 MSIQUERY * view;
4438 static const WCHAR ExecSeqQuery[] =
4439 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00004440 '`','P','u','b','l','i','s','h',
4441 'C','o','m','p','o','n','e','n','t','`',0};
Aric Stewart072c5e52005-04-20 12:50:05 +00004442
4443 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4444 if (rc != ERROR_SUCCESS)
4445 return ERROR_SUCCESS;
4446
4447 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4448 msiobj_release(&view->hdr);
4449
4450 return rc;
4451}
Mike McCormack202166c2005-09-23 10:09:18 +00004452
James Hawkins9bc12ad2006-10-19 15:49:54 -07004453static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4454{
4455 MSIPACKAGE *package = (MSIPACKAGE*)param;
4456 MSIRECORD *row;
4457 MSIFILE *file;
4458 SC_HANDLE hscm, service = NULL;
James Hawkinsde4cab22008-03-11 18:08:57 -05004459 LPCWSTR comp, depends, pass;
Marcus Meissnerdb71fb12008-03-13 21:54:48 +01004460 LPWSTR name = NULL, disp = NULL;
James Hawkins9bc12ad2006-10-19 15:49:54 -07004461 LPCWSTR load_order, serv_name, key;
4462 DWORD serv_type, start_type;
4463 DWORD err_control;
4464
4465 static const WCHAR query[] =
4466 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4467 '`','C','o','m','p','o','n','e','n','t','`',' ',
4468 'W','H','E','R','E',' ',
4469 '`','C','o','m','p','o','n','e','n','t','`',' ',
4470 '=','\'','%','s','\'',0};
4471
4472 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4473 if (!hscm)
4474 {
4475 ERR("Failed to open the SC Manager!\n");
4476 goto done;
4477 }
4478
4479 start_type = MSI_RecordGetInteger(rec, 5);
4480 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4481 goto done;
4482
4483 depends = MSI_RecordGetString(rec, 8);
4484 if (depends && *depends)
4485 FIXME("Dependency list unhandled!\n");
4486
James Hawkinsde4cab22008-03-11 18:08:57 -05004487 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4488 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07004489 serv_type = MSI_RecordGetInteger(rec, 4);
4490 err_control = MSI_RecordGetInteger(rec, 6);
4491 load_order = MSI_RecordGetString(rec, 7);
4492 serv_name = MSI_RecordGetString(rec, 9);
4493 pass = MSI_RecordGetString(rec, 10);
4494 comp = MSI_RecordGetString(rec, 12);
4495
4496 /* fetch the service path */
4497 row = MSI_QueryGetRecord(package->db, query, comp);
4498 if (!row)
4499 {
4500 ERR("Control query failed!\n");
4501 goto done;
4502 }
4503
4504 key = MSI_RecordGetString(row, 6);
James Hawkins9bc12ad2006-10-19 15:49:54 -07004505
4506 file = get_loaded_file(package, key);
James Hawkinsb6cfc402007-10-23 03:06:59 -05004507 msiobj_release(&row->hdr);
James Hawkins9bc12ad2006-10-19 15:49:54 -07004508 if (!file)
4509 {
4510 ERR("Failed to load the service file\n");
4511 goto done;
4512 }
4513
4514 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4515 start_type, err_control, file->TargetPath,
4516 load_order, NULL, NULL, serv_name, pass);
4517 if (!service)
4518 {
4519 if (GetLastError() != ERROR_SERVICE_EXISTS)
4520 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4521 }
4522
4523done:
4524 CloseServiceHandle(service);
4525 CloseServiceHandle(hscm);
James Hawkinsde4cab22008-03-11 18:08:57 -05004526 msi_free(name);
4527 msi_free(disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07004528
4529 return ERROR_SUCCESS;
4530}
4531
4532static UINT ACTION_InstallServices( MSIPACKAGE *package )
4533{
4534 UINT rc;
4535 MSIQUERY * view;
4536 static const WCHAR ExecSeqQuery[] =
4537 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4538 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4539
4540 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4541 if (rc != ERROR_SUCCESS)
4542 return ERROR_SUCCESS;
4543
4544 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4545 msiobj_release(&view->hdr);
4546
4547 return rc;
4548}
4549
James Hawkins58bb3572006-12-01 13:22:59 -08004550/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
James Hawkinscf8e9e32007-11-05 04:37:44 -05004551static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
James Hawkins58bb3572006-12-01 13:22:59 -08004552{
Lionel Debroux99ad76c2007-12-30 19:01:09 +01004553 LPCWSTR *vector, *temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08004554 LPWSTR p, q;
4555 DWORD sep_len;
4556
4557 static const WCHAR separator[] = {'[','~',']',0};
4558
4559 *numargs = 0;
4560 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4561
4562 if (!args)
4563 return NULL;
4564
4565 vector = msi_alloc(sizeof(LPWSTR));
4566 if (!vector)
4567 return NULL;
4568
4569 p = args;
4570 do
4571 {
4572 (*numargs)++;
4573 vector[*numargs - 1] = p;
4574
4575 if ((q = strstrW(p, separator)))
4576 {
4577 *q = '\0';
4578
Lionel Debroux99ad76c2007-12-30 19:01:09 +01004579 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4580 if (!temp_vector)
4581 {
4582 msi_free(vector);
James Hawkins58bb3572006-12-01 13:22:59 -08004583 return NULL;
Lionel Debroux99ad76c2007-12-30 19:01:09 +01004584 }
4585 vector = temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08004586
4587 p = q + sep_len;
4588 }
4589 } while (q);
4590
4591 return vector;
4592}
4593
James Hawkins58bb3572006-12-01 13:22:59 -08004594static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4595{
4596 MSIPACKAGE *package = (MSIPACKAGE *)param;
4597 MSICOMPONENT *comp;
4598 SC_HANDLE scm, service = NULL;
4599 LPCWSTR name, *vector = NULL;
4600 LPWSTR args;
4601 DWORD event, numargs;
4602 UINT r = ERROR_FUNCTION_FAILED;
4603
James Hawkinseec9bbb2007-11-01 03:10:47 -05004604 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
James Hawkins58bb3572006-12-01 13:22:59 -08004605 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4606 return ERROR_SUCCESS;
4607
4608 name = MSI_RecordGetString(rec, 2);
4609 event = MSI_RecordGetInteger(rec, 3);
4610 args = strdupW(MSI_RecordGetString(rec, 4));
4611
4612 if (!(event & msidbServiceControlEventStart))
4613 return ERROR_SUCCESS;
4614
4615 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4616 if (!scm)
4617 {
4618 ERR("Failed to open the service control manager\n");
4619 goto done;
4620 }
4621
4622 service = OpenServiceW(scm, name, SERVICE_START);
4623 if (!service)
4624 {
Francois Gougetaab5e582007-01-18 11:40:15 +01004625 ERR("Failed to open service %s\n", debugstr_w(name));
James Hawkins58bb3572006-12-01 13:22:59 -08004626 goto done;
4627 }
4628
James Hawkinscf8e9e32007-11-05 04:37:44 -05004629 vector = msi_service_args_to_vector(args, &numargs);
James Hawkins58bb3572006-12-01 13:22:59 -08004630
4631 if (!StartServiceW(service, numargs, vector))
4632 {
Francois Gougetaab5e582007-01-18 11:40:15 +01004633 ERR("Failed to start service %s\n", debugstr_w(name));
James Hawkins58bb3572006-12-01 13:22:59 -08004634 goto done;
4635 }
4636
4637 r = ERROR_SUCCESS;
4638
4639done:
4640 CloseServiceHandle(service);
4641 CloseServiceHandle(scm);
4642
4643 msi_free(args);
4644 msi_free(vector);
4645 return r;
4646}
4647
4648static UINT ACTION_StartServices( MSIPACKAGE *package )
4649{
4650 UINT rc;
4651 MSIQUERY *view;
4652
4653 static const WCHAR query[] = {
4654 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4655 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4656
4657 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4658 if (rc != ERROR_SUCCESS)
4659 return ERROR_SUCCESS;
4660
4661 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4662 msiobj_release(&view->hdr);
4663
4664 return rc;
4665}
4666
James Hawkinsfb508ff2008-03-24 01:31:07 -05004667static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
4668{
4669 DWORD i, needed, count;
4670 ENUM_SERVICE_STATUSW *dependencies;
4671 SERVICE_STATUS ss;
4672 SC_HANDLE depserv;
4673
4674 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
4675 0, &needed, &count))
4676 return TRUE;
4677
4678 if (GetLastError() != ERROR_MORE_DATA)
4679 return FALSE;
4680
4681 dependencies = msi_alloc(needed);
4682 if (!dependencies)
4683 return FALSE;
4684
4685 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
4686 needed, &needed, &count))
4687 goto error;
4688
4689 for (i = 0; i < count; i++)
4690 {
4691 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
4692 SERVICE_STOP | SERVICE_QUERY_STATUS);
4693 if (!depserv)
4694 goto error;
4695
4696 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
4697 goto error;
4698 }
4699
4700 return TRUE;
4701
4702error:
4703 msi_free(dependencies);
4704 return FALSE;
4705}
4706
4707static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param)
4708{
4709 MSIPACKAGE *package = (MSIPACKAGE *)param;
4710 MSICOMPONENT *comp;
4711 SERVICE_STATUS status;
4712 SERVICE_STATUS_PROCESS ssp;
4713 SC_HANDLE scm = NULL, service = NULL;
4714 LPWSTR name, args;
4715 DWORD event, needed;
4716
4717 event = MSI_RecordGetInteger(rec, 3);
4718 if (!(event & msidbServiceControlEventStop))
4719 return ERROR_SUCCESS;
4720
4721 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
4722 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4723 return ERROR_SUCCESS;
4724
4725 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
4726 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
4727 args = strdupW(MSI_RecordGetString(rec, 4));
4728
4729 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
4730 if (!scm)
4731 {
4732 WARN("Failed to open the SCM: %d\n", GetLastError());
4733 goto done;
4734 }
4735
4736 service = OpenServiceW(scm, name,
4737 SERVICE_STOP |
4738 SERVICE_QUERY_STATUS |
4739 SERVICE_ENUMERATE_DEPENDENTS);
4740 if (!service)
4741 {
4742 WARN("Failed to open service (%s): %d\n",
4743 debugstr_w(name), GetLastError());
4744 goto done;
4745 }
4746
4747 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
4748 sizeof(SERVICE_STATUS_PROCESS), &needed))
4749 {
4750 WARN("Failed to query service status (%s): %d\n",
4751 debugstr_w(name), GetLastError());
4752 goto done;
4753 }
4754
4755 if (ssp.dwCurrentState == SERVICE_STOPPED)
4756 goto done;
4757
4758 stop_service_dependents(scm, service);
4759
James Hawkinsddfefc02008-03-24 16:16:58 -05004760 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
James Hawkinsfb508ff2008-03-24 01:31:07 -05004761 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
4762
4763done:
4764 CloseServiceHandle(service);
4765 CloseServiceHandle(scm);
4766 msi_free(name);
4767 msi_free(args);
4768
4769 return ERROR_SUCCESS;
4770}
4771
4772static UINT ACTION_StopServices( MSIPACKAGE *package )
4773{
4774 UINT rc;
4775 MSIQUERY *view;
4776
4777 static const WCHAR query[] = {
4778 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4779 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4780
4781 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4782 if (rc != ERROR_SUCCESS)
4783 return ERROR_SUCCESS;
4784
4785 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
4786 msiobj_release(&view->hdr);
4787
4788 return rc;
4789}
4790
James Hawkinsd3bec322006-11-27 18:20:33 -08004791static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4792{
4793 MSIFILE *file;
4794
4795 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4796 {
4797 if (!lstrcmpW(file->File, filename))
4798 return file;
4799 }
4800
4801 return NULL;
4802}
4803
4804static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4805{
4806 MSIPACKAGE *package = (MSIPACKAGE*)param;
4807 LPWSTR driver, driver_path, ptr;
4808 WCHAR outpath[MAX_PATH];
4809 MSIFILE *driver_file, *setup_file;
4810 LPCWSTR desc;
4811 DWORD len, usage;
4812 UINT r = ERROR_SUCCESS;
4813
4814 static const WCHAR driver_fmt[] = {
4815 'D','r','i','v','e','r','=','%','s',0};
4816 static const WCHAR setup_fmt[] = {
4817 'S','e','t','u','p','=','%','s',0};
4818 static const WCHAR usage_fmt[] = {
4819 'F','i','l','e','U','s','a','g','e','=','1',0};
4820
4821 desc = MSI_RecordGetString(rec, 3);
4822
4823 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4824 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4825
4826 if (!driver_file || !setup_file)
4827 {
4828 ERR("ODBC Driver entry not found!\n");
4829 return ERROR_FUNCTION_FAILED;
4830 }
4831
4832 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4833 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4834 lstrlenW(usage_fmt) + 1;
4835 driver = msi_alloc(len * sizeof(WCHAR));
4836 if (!driver)
4837 return ERROR_OUTOFMEMORY;
4838
4839 ptr = driver;
4840 lstrcpyW(ptr, desc);
4841 ptr += lstrlenW(ptr) + 1;
4842
4843 sprintfW(ptr, driver_fmt, driver_file->FileName);
4844 ptr += lstrlenW(ptr) + 1;
4845
4846 sprintfW(ptr, setup_fmt, setup_file->FileName);
4847 ptr += lstrlenW(ptr) + 1;
4848
4849 lstrcpyW(ptr, usage_fmt);
4850 ptr += lstrlenW(ptr) + 1;
4851 *ptr = '\0';
4852
4853 driver_path = strdupW(driver_file->TargetPath);
4854 ptr = strrchrW(driver_path, '\\');
4855 if (ptr) *ptr = '\0';
4856
4857 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4858 NULL, ODBC_INSTALL_COMPLETE, &usage))
4859 {
4860 ERR("Failed to install SQL driver!\n");
4861 r = ERROR_FUNCTION_FAILED;
4862 }
4863
4864 msi_free(driver);
4865 msi_free(driver_path);
4866
4867 return r;
4868}
4869
Hans Leidekker33c025b2007-04-22 11:37:51 +02004870static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4871{
4872 MSIPACKAGE *package = (MSIPACKAGE*)param;
4873 LPWSTR translator, translator_path, ptr;
4874 WCHAR outpath[MAX_PATH];
4875 MSIFILE *translator_file, *setup_file;
4876 LPCWSTR desc;
4877 DWORD len, usage;
4878 UINT r = ERROR_SUCCESS;
4879
4880 static const WCHAR translator_fmt[] = {
4881 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4882 static const WCHAR setup_fmt[] = {
4883 'S','e','t','u','p','=','%','s',0};
4884
4885 desc = MSI_RecordGetString(rec, 3);
4886
4887 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4888 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4889
4890 if (!translator_file || !setup_file)
4891 {
4892 ERR("ODBC Translator entry not found!\n");
4893 return ERROR_FUNCTION_FAILED;
4894 }
4895
4896 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4897 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4898 translator = msi_alloc(len * sizeof(WCHAR));
4899 if (!translator)
4900 return ERROR_OUTOFMEMORY;
4901
4902 ptr = translator;
4903 lstrcpyW(ptr, desc);
4904 ptr += lstrlenW(ptr) + 1;
4905
4906 sprintfW(ptr, translator_fmt, translator_file->FileName);
4907 ptr += lstrlenW(ptr) + 1;
4908
4909 sprintfW(ptr, setup_fmt, setup_file->FileName);
4910 ptr += lstrlenW(ptr) + 1;
4911 *ptr = '\0';
4912
4913 translator_path = strdupW(translator_file->TargetPath);
4914 ptr = strrchrW(translator_path, '\\');
4915 if (ptr) *ptr = '\0';
4916
4917 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4918 NULL, ODBC_INSTALL_COMPLETE, &usage))
4919 {
4920 ERR("Failed to install SQL translator!\n");
4921 r = ERROR_FUNCTION_FAILED;
4922 }
4923
4924 msi_free(translator);
4925 msi_free(translator_path);
4926
4927 return r;
4928}
4929
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02004930static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4931{
4932 LPWSTR attrs;
4933 LPCWSTR desc, driver;
4934 WORD request = ODBC_ADD_SYS_DSN;
4935 INT registration;
4936 DWORD len;
4937 UINT r = ERROR_SUCCESS;
4938
4939 static const WCHAR attrs_fmt[] = {
4940 'D','S','N','=','%','s',0 };
4941
4942 desc = MSI_RecordGetString(rec, 3);
4943 driver = MSI_RecordGetString(rec, 4);
4944 registration = MSI_RecordGetInteger(rec, 5);
4945
4946 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4947 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4948
4949 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4950 attrs = msi_alloc(len * sizeof(WCHAR));
4951 if (!attrs)
4952 return ERROR_OUTOFMEMORY;
4953
4954 sprintfW(attrs, attrs_fmt, desc);
4955 attrs[len - 1] = '\0';
4956
4957 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4958 {
4959 ERR("Failed to install SQL data source!\n");
4960 r = ERROR_FUNCTION_FAILED;
4961 }
4962
4963 msi_free(attrs);
4964
4965 return r;
4966}
4967
James Hawkinsd3bec322006-11-27 18:20:33 -08004968static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4969{
4970 UINT rc;
4971 MSIQUERY *view;
4972
Hans Leidekker33c025b2007-04-22 11:37:51 +02004973 static const WCHAR driver_query[] = {
James Hawkinsd3bec322006-11-27 18:20:33 -08004974 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4975 'O','D','B','C','D','r','i','v','e','r',0 };
4976
Hans Leidekker33c025b2007-04-22 11:37:51 +02004977 static const WCHAR translator_query[] = {
4978 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4979 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4980
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02004981 static const WCHAR source_query[] = {
4982 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4983 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4984
Hans Leidekker33c025b2007-04-22 11:37:51 +02004985 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
James Hawkinsd3bec322006-11-27 18:20:33 -08004986 if (rc != ERROR_SUCCESS)
4987 return ERROR_SUCCESS;
4988
4989 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4990 msiobj_release(&view->hdr);
4991
Hans Leidekker33c025b2007-04-22 11:37:51 +02004992 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4993 if (rc != ERROR_SUCCESS)
4994 return ERROR_SUCCESS;
4995
4996 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4997 msiobj_release(&view->hdr);
4998
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02004999 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5000 if (rc != ERROR_SUCCESS)
5001 return ERROR_SUCCESS;
5002
5003 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5004 msiobj_release(&view->hdr);
5005
James Hawkinsd3bec322006-11-27 18:20:33 -08005006 return rc;
5007}
5008
James Hawkins5b8641a2007-05-30 10:57:31 -07005009#define ENV_ACT_SETALWAYS 0x1
5010#define ENV_ACT_SETABSENT 0x2
5011#define ENV_ACT_REMOVE 0x4
James Hawkins881f5922007-06-13 17:46:09 -07005012#define ENV_ACT_REMOVEMATCH 0x8
James Hawkins5b8641a2007-05-30 10:57:31 -07005013
5014#define ENV_MOD_MACHINE 0x20000000
5015#define ENV_MOD_APPEND 0x40000000
5016#define ENV_MOD_PREFIX 0x80000000
James Hawkins881f5922007-06-13 17:46:09 -07005017#define ENV_MOD_MASK 0xC0000000
5018
5019#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
5020
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005021static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
James Hawkins881f5922007-06-13 17:46:09 -07005022{
5023 LPCWSTR cptr = *name;
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005024 LPCWSTR ptr = *value;
James Hawkins881f5922007-06-13 17:46:09 -07005025
5026 static const WCHAR prefix[] = {'[','~',']',0};
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005027 static const int prefix_len = 3;
James Hawkins881f5922007-06-13 17:46:09 -07005028
5029 *flags = 0;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005030 while (*cptr)
James Hawkins881f5922007-06-13 17:46:09 -07005031 {
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005032 if (*cptr == '=')
James Hawkins881f5922007-06-13 17:46:09 -07005033 *flags |= ENV_ACT_SETALWAYS;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005034 else if (*cptr == '+')
James Hawkins881f5922007-06-13 17:46:09 -07005035 *flags |= ENV_ACT_SETABSENT;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005036 else if (*cptr == '-')
James Hawkins881f5922007-06-13 17:46:09 -07005037 *flags |= ENV_ACT_REMOVE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005038 else if (*cptr == '!')
James Hawkins881f5922007-06-13 17:46:09 -07005039 *flags |= ENV_ACT_REMOVEMATCH;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005040 else if (*cptr == '*')
James Hawkins881f5922007-06-13 17:46:09 -07005041 *flags |= ENV_MOD_MACHINE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09005042 else
James Hawkins881f5922007-06-13 17:46:09 -07005043 break;
James Hawkins881f5922007-06-13 17:46:09 -07005044
5045 cptr++;
5046 (*name)++;
5047 }
5048
5049 if (!*cptr)
5050 {
5051 ERR("Missing environment variable\n");
5052 return ERROR_FUNCTION_FAILED;
5053 }
5054
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005055 if (!strncmpW(ptr, prefix, prefix_len))
James Hawkins881f5922007-06-13 17:46:09 -07005056 {
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005057 *flags |= ENV_MOD_APPEND;
James Hawkins881f5922007-06-13 17:46:09 -07005058 *value += lstrlenW(prefix);
5059 }
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005060 else if (lstrlenW(*value) >= prefix_len)
James Hawkins881f5922007-06-13 17:46:09 -07005061 {
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005062 ptr += lstrlenW(ptr) - prefix_len;
James Hawkins881f5922007-06-13 17:46:09 -07005063 if (!lstrcmpW(ptr, prefix))
5064 {
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005065 *flags |= ENV_MOD_PREFIX;
5066 /* the "[~]" will be removed by deformat_string */;
James Hawkins881f5922007-06-13 17:46:09 -07005067 }
5068 }
5069
5070 if (!*flags ||
5071 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
5072 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
5073 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
5074 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
5075 {
5076 ERR("Invalid flags: %08x\n", *flags);
5077 return ERROR_FUNCTION_FAILED;
5078 }
5079
5080 return ERROR_SUCCESS;
5081}
James Hawkins5b8641a2007-05-30 10:57:31 -07005082
5083static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
5084{
James Hawkins881f5922007-06-13 17:46:09 -07005085 MSIPACKAGE *package = param;
Andrew Talbot68975932008-04-21 22:23:21 +01005086 LPCWSTR name, value;
James Hawkins881f5922007-06-13 17:46:09 -07005087 LPWSTR data = NULL, newval = NULL;
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005088 LPWSTR deformatted = NULL, ptr;
James Hawkins5b8641a2007-05-30 10:57:31 -07005089 DWORD flags, type, size;
5090 LONG res;
James Hawkins9d712382007-11-05 04:47:12 -05005091 HKEY env = NULL, root;
5092 LPCWSTR environment;
James Hawkins5b8641a2007-05-30 10:57:31 -07005093
James Hawkins9d712382007-11-05 04:47:12 -05005094 static const WCHAR user_env[] =
5095 {'E','n','v','i','r','o','n','m','e','n','t',0};
5096 static const WCHAR machine_env[] =
James Hawkins5b8641a2007-05-30 10:57:31 -07005097 {'S','y','s','t','e','m','\\',
5098 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
5099 'C','o','n','t','r','o','l','\\',
5100 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
5101 'E','n','v','i','r','o','n','m','e','n','t',0};
5102 static const WCHAR semicolon[] = {';',0};
5103
James Hawkins881f5922007-06-13 17:46:09 -07005104 name = MSI_RecordGetString(rec, 2);
5105 value = MSI_RecordGetString(rec, 3);
James Hawkins5b8641a2007-05-30 10:57:31 -07005106
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005107 res = env_set_flags(&name, &value, &flags);
James Hawkins881f5922007-06-13 17:46:09 -07005108 if (res != ERROR_SUCCESS)
5109 goto done;
5110
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07005111 deformat_string(package, value, &deformatted);
5112 if (!deformatted)
5113 {
5114 res = ERROR_OUTOFMEMORY;
5115 goto done;
5116 }
5117
James Hawkins881f5922007-06-13 17:46:09 -07005118 value = deformatted;
James Hawkins5b8641a2007-05-30 10:57:31 -07005119
5120 if (flags & ENV_MOD_MACHINE)
James Hawkins9d712382007-11-05 04:47:12 -05005121 {
5122 environment = machine_env;
James Hawkins5b8641a2007-05-30 10:57:31 -07005123 root = HKEY_LOCAL_MACHINE;
James Hawkins9d712382007-11-05 04:47:12 -05005124 }
5125 else
5126 {
5127 environment = user_env;
5128 root = HKEY_CURRENT_USER;
5129 }
James Hawkins5b8641a2007-05-30 10:57:31 -07005130
James Hawkins9d712382007-11-05 04:47:12 -05005131 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
5132 KEY_ALL_ACCESS, NULL, &env, NULL);
James Hawkins5b8641a2007-05-30 10:57:31 -07005133 if (res != ERROR_SUCCESS)
James Hawkins881f5922007-06-13 17:46:09 -07005134 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07005135
5136 if (flags & ENV_ACT_REMOVE)
James Hawkins881f5922007-06-13 17:46:09 -07005137 FIXME("Not removing environment variable on uninstall!\n");
James Hawkins5b8641a2007-05-30 10:57:31 -07005138
5139 size = 0;
James Hawkins881f5922007-06-13 17:46:09 -07005140 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
5141 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
James Hawkins31c461e2008-01-05 11:46:09 -06005142 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
James Hawkins881f5922007-06-13 17:46:09 -07005143 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07005144
5145 if (res != ERROR_FILE_NOT_FOUND)
5146 {
5147 if (flags & ENV_ACT_SETABSENT)
5148 {
5149 res = ERROR_SUCCESS;
5150 goto done;
5151 }
5152
James Hawkins881f5922007-06-13 17:46:09 -07005153 data = msi_alloc(size);
5154 if (!data)
5155 {
5156 RegCloseKey(env);
5157 return ERROR_OUTOFMEMORY;
5158 }
5159
5160 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5161 if (res != ERROR_SUCCESS)
5162 goto done;
5163
5164 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5165 {
5166 res = RegDeleteKeyW(env, name);
5167 goto done;
5168 }
5169
5170 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5171 newval = msi_alloc(size);
5172 ptr = newval;
5173 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07005174 {
5175 res = ERROR_OUTOFMEMORY;
5176 goto done;
5177 }
5178
James Hawkins881f5922007-06-13 17:46:09 -07005179 if (!(flags & ENV_MOD_MASK))
5180 lstrcpyW(newval, value);
5181 else
James Hawkins5b8641a2007-05-30 10:57:31 -07005182 {
James Hawkins881f5922007-06-13 17:46:09 -07005183 if (flags & ENV_MOD_PREFIX)
5184 {
5185 lstrcpyW(newval, value);
5186 lstrcatW(newval, semicolon);
5187 ptr = newval + lstrlenW(value) + 1;
5188 }
James Hawkins5b8641a2007-05-30 10:57:31 -07005189
James Hawkins881f5922007-06-13 17:46:09 -07005190 lstrcpyW(ptr, data);
James Hawkins5b8641a2007-05-30 10:57:31 -07005191
James Hawkins881f5922007-06-13 17:46:09 -07005192 if (flags & ENV_MOD_APPEND)
5193 {
5194 lstrcatW(newval, semicolon);
5195 lstrcatW(newval, value);
5196 }
James Hawkins5b8641a2007-05-30 10:57:31 -07005197 }
5198 }
5199 else
5200 {
5201 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
James Hawkins881f5922007-06-13 17:46:09 -07005202 newval = msi_alloc(size);
5203 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07005204 {
5205 res = ERROR_OUTOFMEMORY;
5206 goto done;
5207 }
5208
James Hawkins881f5922007-06-13 17:46:09 -07005209 lstrcpyW(newval, value);
James Hawkins5b8641a2007-05-30 10:57:31 -07005210 }
5211
James Hawkins881f5922007-06-13 17:46:09 -07005212 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5213 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
James Hawkins5b8641a2007-05-30 10:57:31 -07005214
5215done:
Andrew Talbot0e4ccb82007-06-23 17:28:50 +01005216 if (env) RegCloseKey(env);
James Hawkins881f5922007-06-13 17:46:09 -07005217 msi_free(deformatted);
5218 msi_free(data);
5219 msi_free(newval);
James Hawkins5b8641a2007-05-30 10:57:31 -07005220 return res;
5221}
5222
5223static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5224{
5225 UINT rc;
5226 MSIQUERY * view;
5227 static const WCHAR ExecSeqQuery[] =
5228 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5229 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5230 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5231 if (rc != ERROR_SUCCESS)
5232 return ERROR_SUCCESS;
5233
5234 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5235 msiobj_release(&view->hdr);
5236
5237 return rc;
5238}
5239
James Hawkinsc3df74e2007-11-01 03:09:02 -05005240#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5241
5242typedef struct
5243{
5244 struct list entry;
5245 LPWSTR sourcename;
5246 LPWSTR destname;
5247 LPWSTR source;
5248 LPWSTR dest;
5249} FILE_LIST;
5250
5251static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5252{
5253 BOOL ret;
5254
5255 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5256 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5257 {
5258 WARN("Source or dest is directory, not moving\n");
5259 return FALSE;
5260 }
5261
5262 if (options == msidbMoveFileOptionsMove)
5263 {
5264 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5265 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5266 if (!ret)
5267 {
5268 WARN("MoveFile failed: %d\n", GetLastError());
5269 return FALSE;
5270 }
5271 }
5272 else
5273 {
5274 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5275 ret = CopyFileW(source, dest, FALSE);
5276 if (!ret)
5277 {
5278 WARN("CopyFile failed: %d\n", GetLastError());
5279 return FALSE;
5280 }
5281 }
5282
5283 return TRUE;
5284}
5285
5286static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5287{
5288 LPWSTR path, ptr;
5289 DWORD dirlen, pathlen;
5290
5291 ptr = strrchrW(wildcard, '\\');
5292 dirlen = ptr - wildcard + 1;
5293
5294 pathlen = dirlen + lstrlenW(filename) + 1;
5295 path = msi_alloc(pathlen * sizeof(WCHAR));
5296
5297 lstrcpynW(path, wildcard, dirlen + 1);
5298 lstrcatW(path, filename);
5299
5300 return path;
5301}
5302
5303static void free_file_entry(FILE_LIST *file)
5304{
5305 msi_free(file->source);
5306 msi_free(file->dest);
5307 msi_free(file);
5308}
5309
5310static void free_list(FILE_LIST *list)
5311{
5312 while (!list_empty(&list->entry))
5313 {
5314 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5315
5316 list_remove(&file->entry);
5317 free_file_entry(file);
5318 }
5319}
5320
5321static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5322{
5323 FILE_LIST *new, *file;
5324 LPWSTR ptr, filename;
5325 DWORD size;
5326
5327 new = msi_alloc_zero(sizeof(FILE_LIST));
5328 if (!new)
5329 return FALSE;
5330
5331 new->source = strdupW(source);
5332 ptr = strrchrW(dest, '\\') + 1;
5333 filename = strrchrW(new->source, '\\') + 1;
5334
5335 new->sourcename = filename;
5336
5337 if (*ptr)
5338 new->destname = ptr;
5339 else
5340 new->destname = new->sourcename;
5341
5342 size = (ptr - dest) + lstrlenW(filename) + 1;
5343 new->dest = msi_alloc(size * sizeof(WCHAR));
5344 if (!new->dest)
5345 {
5346 free_file_entry(new);
5347 return FALSE;
5348 }
5349
5350 lstrcpynW(new->dest, dest, ptr - dest + 1);
5351 lstrcatW(new->dest, filename);
5352
5353 if (list_empty(&files->entry))
5354 {
5355 list_add_head(&files->entry, &new->entry);
5356 return TRUE;
5357 }
5358
5359 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5360 {
5361 if (lstrcmpW(source, file->source) < 0)
5362 {
5363 list_add_before(&file->entry, &new->entry);
5364 return TRUE;
5365 }
5366 }
5367
5368 list_add_after(&file->entry, &new->entry);
5369 return TRUE;
5370}
5371
James Hawkins4439e0b2008-02-29 23:29:43 -06005372static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
James Hawkinsc3df74e2007-11-01 03:09:02 -05005373{
5374 WIN32_FIND_DATAW wfd;
5375 HANDLE hfile;
5376 LPWSTR path;
5377 BOOL res;
5378 FILE_LIST files, *file;
5379 DWORD size;
5380
5381 hfile = FindFirstFileW(source, &wfd);
5382 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5383
5384 list_init(&files.entry);
5385
5386 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5387 {
5388 if (is_dot_dir(wfd.cFileName)) continue;
5389
5390 path = wildcard_to_file(source, wfd.cFileName);
5391 if (!path)
5392 {
James Hawkinsfa8476e2007-12-13 18:38:33 -06005393 res = FALSE;
5394 goto done;
James Hawkinsc3df74e2007-11-01 03:09:02 -05005395 }
5396
5397 add_wildcard(&files, path, dest);
5398 msi_free(path);
5399 }
5400
James Hawkinsa7d02a12008-04-02 17:41:47 -05005401 /* no files match the wildcard */
5402 if (list_empty(&files.entry))
5403 goto done;
5404
James Hawkinsc3df74e2007-11-01 03:09:02 -05005405 /* only the first wildcard match gets renamed to dest */
5406 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5407 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5408 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5409 if (!file->dest)
5410 {
James Hawkinsfa8476e2007-12-13 18:38:33 -06005411 res = FALSE;
5412 goto done;
James Hawkinsc3df74e2007-11-01 03:09:02 -05005413 }
5414
5415 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5416
5417 while (!list_empty(&files.entry))
5418 {
5419 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5420
5421 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5422
5423 list_remove(&file->entry);
5424 free_file_entry(file);
5425 }
5426
James Hawkinsfa8476e2007-12-13 18:38:33 -06005427 res = TRUE;
5428
5429done:
5430 free_list(&files);
5431 FindClose(hfile);
5432 return res;
James Hawkinsc3df74e2007-11-01 03:09:02 -05005433}
5434
5435static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5436{
5437 MSIPACKAGE *package = param;
5438 MSICOMPONENT *comp;
5439 LPCWSTR sourcename, destname;
5440 LPWSTR sourcedir = NULL, destdir = NULL;
5441 LPWSTR source = NULL, dest = NULL;
5442 int options;
5443 DWORD size;
5444 BOOL ret, wildcards;
5445
5446 static const WCHAR backslash[] = {'\\',0};
5447
5448 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5449 if (!comp || !comp->Enabled ||
5450 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5451 {
5452 TRACE("Component not set for install, not moving file\n");
5453 return ERROR_SUCCESS;
5454 }
5455
5456 sourcename = MSI_RecordGetString(rec, 3);
5457 destname = MSI_RecordGetString(rec, 4);
5458 options = MSI_RecordGetInteger(rec, 7);
5459
5460 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5461 if (!sourcedir)
5462 goto done;
5463
5464 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5465 if (!destdir)
5466 goto done;
5467
5468 if (!sourcename)
5469 {
5470 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5471 goto done;
5472
5473 source = strdupW(sourcedir);
5474 if (!source)
5475 goto done;
5476 }
5477 else
5478 {
5479 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5480 source = msi_alloc(size * sizeof(WCHAR));
5481 if (!source)
5482 goto done;
5483
5484 lstrcpyW(source, sourcedir);
5485 if (source[lstrlenW(source) - 1] != '\\')
5486 lstrcatW(source, backslash);
5487 lstrcatW(source, sourcename);
5488 }
5489
5490 wildcards = strchrW(source, '*') || strchrW(source, '?');
5491
5492 if (!destname && !wildcards)
5493 {
5494 destname = strdupW(sourcename);
5495 if (!destname)
5496 goto done;
5497 }
5498
5499 size = 0;
5500 if (destname)
5501 size = lstrlenW(destname);
5502
5503 size += lstrlenW(destdir) + 2;
5504 dest = msi_alloc(size * sizeof(WCHAR));
5505 if (!dest)
5506 goto done;
5507
5508 lstrcpyW(dest, destdir);
5509 if (dest[lstrlenW(dest) - 1] != '\\')
5510 lstrcatW(dest, backslash);
5511
5512 if (destname)
5513 lstrcatW(dest, destname);
5514
5515 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5516 {
5517 ret = CreateDirectoryW(destdir, NULL);
5518 if (!ret)
5519 {
5520 WARN("CreateDirectory failed: %d\n", GetLastError());
5521 return ERROR_SUCCESS;
5522 }
5523 }
5524
5525 if (!wildcards)
5526 msi_move_file(source, dest, options);
5527 else
5528 move_files_wildcard(source, dest, options);
5529
5530done:
5531 msi_free(sourcedir);
5532 msi_free(destdir);
5533 msi_free(source);
5534 msi_free(dest);
5535
5536 return ERROR_SUCCESS;
5537}
5538
5539static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5540{
5541 UINT rc;
5542 MSIQUERY *view;
5543
5544 static const WCHAR ExecSeqQuery[] =
5545 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5546 '`','M','o','v','e','F','i','l','e','`',0};
5547
5548 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5549 if (rc != ERROR_SUCCESS)
5550 return ERROR_SUCCESS;
5551
5552 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5553 msiobj_release(&view->hdr);
5554
5555 return rc;
5556}
5557
James Hawkinsbfe07d12008-04-30 04:22:46 -05005558static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
5559 DWORD dwReserved);
5560static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
5561 LPVOID pvReserved, HMODULE *phModDll);
5562
5563static BOOL init_functionpointers(void)
5564{
5565 HRESULT hr;
5566 HMODULE hfusion;
5567 HMODULE hmscoree;
5568
5569 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
5570
5571 hmscoree = LoadLibraryA("mscoree.dll");
5572 if (!hmscoree)
5573 {
5574 WARN("mscoree.dll not available\n");
5575 return FALSE;
5576 }
5577
5578 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
5579 if (!pLoadLibraryShim)
5580 {
5581 WARN("LoadLibraryShim not available\n");
5582 FreeLibrary(hmscoree);
5583 return FALSE;
5584 }
5585
5586 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
5587 if (FAILED(hr))
5588 {
5589 WARN("fusion.dll not available\n");
5590 FreeLibrary(hmscoree);
5591 return FALSE;
5592 }
5593
5594 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
5595
5596 FreeLibrary(hmscoree);
5597 return TRUE;
5598}
5599
5600static UINT install_assembly(LPWSTR path)
5601{
5602 IAssemblyCache *cache;
5603 HRESULT hr;
5604 UINT r = ERROR_FUNCTION_FAILED;
5605
5606 if (!init_functionpointers() || !pCreateAssemblyCache)
5607 return ERROR_FUNCTION_FAILED;
5608
5609 hr = pCreateAssemblyCache(&cache, 0);
5610 if (FAILED(hr))
5611 goto done;
5612
5613 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
5614 if (FAILED(hr))
5615 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
5616
5617 r = ERROR_SUCCESS;
5618
5619done:
5620 IAssemblyCache_Release(cache);
5621 return r;
5622}
5623
5624static UINT ITERATE_PublishAssembly( MSIRECORD *rec, LPVOID param )
5625{
5626 MSIPACKAGE *package = param;
5627 MSICOMPONENT *comp;
5628 MSIFEATURE *feature;
5629 MSIFILE *file;
5630 WCHAR path[MAX_PATH];
5631 LPCWSTR app;
5632 DWORD attr;
5633 UINT r;
5634
5635 comp = get_loaded_component(package, MSI_RecordGetString(rec, 1));
5636 if (!comp || !comp->Enabled ||
5637 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5638 {
5639 ERR("Component not set for install, not publishing assembly\n");
5640 return ERROR_SUCCESS;
5641 }
5642
5643 feature = find_feature_by_name(package, MSI_RecordGetString(rec, 2));
5644 if (feature)
5645 msi_feature_set_state(feature, INSTALLSTATE_LOCAL);
5646
5647 if (MSI_RecordGetString(rec, 3))
5648 FIXME("Manifest unhandled\n");
5649
5650 app = MSI_RecordGetString(rec, 4);
5651 if (app)
5652 {
5653 FIXME("Assembly should be privately installed\n");
5654 return ERROR_SUCCESS;
5655 }
5656
5657 attr = MSI_RecordGetInteger(rec, 5);
5658 if (attr == msidbAssemblyAttributesWin32)
5659 {
5660 FIXME("Win32 assemblies not handled\n");
5661 return ERROR_SUCCESS;
5662 }
5663
5664 /* FIXME: extract all files belonging to this component */
5665 file = msi_find_file(package, comp->KeyPath);
James Hawkins70cd6bf2008-05-20 00:35:42 -05005666 if (!file)
5667 {
5668 ERR("File %s not found\n", debugstr_w(comp->KeyPath));
5669 return ERROR_FUNCTION_FAILED;
5670 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05005671
5672 GetTempPathW(MAX_PATH, path);
James Hawkinsbfe07d12008-04-30 04:22:46 -05005673
James Hawkins9460ae32008-05-13 18:24:48 -05005674 if (file->IsCompressed)
5675 {
5676 r = msi_extract_file(package, file, path);
5677 if (r != ERROR_SUCCESS)
5678 {
5679 ERR("Failed to extract temporary assembly\n");
5680 return r;
5681 }
5682
5683 PathAddBackslashW(path);
5684 lstrcatW(path, file->FileName);
5685 }
5686 else
5687 {
5688 PathAddBackslashW(path);
5689 lstrcatW(path, file->FileName);
5690
5691 if (!CopyFileW(file->SourcePath, path, FALSE))
5692 {
5693 ERR("Failed to copy temporary assembly: %d\n", GetLastError());
5694 return ERROR_FUNCTION_FAILED;
5695 }
5696 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05005697
5698 r = install_assembly(path);
5699 if (r != ERROR_SUCCESS)
5700 ERR("Failed to install assembly\n");
5701
5702 /* FIXME: write Installer assembly reg values */
5703
5704 return r;
5705}
5706
5707static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5708{
5709 UINT rc;
5710 MSIQUERY *view;
5711
5712 static const WCHAR ExecSeqQuery[] =
5713 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5714 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
5715
5716 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5717 if (rc != ERROR_SUCCESS)
5718 return ERROR_SUCCESS;
5719
5720 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishAssembly, package);
5721 msiobj_release(&view->hdr);
5722
5723 return rc;
5724}
5725
Mike McCormack2586a092005-09-26 09:56:18 +00005726static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5727 LPCSTR action, LPCWSTR table )
Mike McCormack567f0312005-09-23 11:06:57 +00005728{
5729 static const WCHAR query[] = {
Mike McCormack2586a092005-09-26 09:56:18 +00005730 'S','E','L','E','C','T',' ','*',' ',
5731 'F','R','O','M',' ','`','%','s','`',0 };
Mike McCormack567f0312005-09-23 11:06:57 +00005732 MSIQUERY *view = NULL;
5733 DWORD count = 0;
Mike McCormack2586a092005-09-26 09:56:18 +00005734 UINT r;
Mike McCormack567f0312005-09-23 11:06:57 +00005735
Mike McCormack2586a092005-09-26 09:56:18 +00005736 r = MSI_OpenQuery( package->db, &view, query, table );
5737 if (r == ERROR_SUCCESS)
Mike McCormack567f0312005-09-23 11:06:57 +00005738 {
Mike McCormack2586a092005-09-26 09:56:18 +00005739 r = MSI_IterateRecords(view, &count, NULL, package);
Mike McCormack567f0312005-09-23 11:06:57 +00005740 msiobj_release(&view->hdr);
5741 }
5742
Mike McCormack2586a092005-09-26 09:56:18 +00005743 if (count)
Mike McCormackf1d46462006-10-05 13:41:22 +09005744 FIXME("%s -> %u ignored %s table values\n",
Mike McCormack2586a092005-09-26 09:56:18 +00005745 action, count, debugstr_w(table));
5746
Mike McCormack567f0312005-09-23 11:06:57 +00005747 return ERROR_SUCCESS;
5748}
Mike McCormack94fbe092005-09-23 17:21:10 +00005749
Mike McCormack55942702005-10-30 19:23:28 +00005750static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5751{
5752 TRACE("%p\n", package);
5753 return ERROR_SUCCESS;
5754}
5755
Mike McCormack2586a092005-09-26 09:56:18 +00005756static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
Mike McCormack94fbe092005-09-23 17:21:10 +00005757{
Mike McCormack2586a092005-09-26 09:56:18 +00005758 static const WCHAR table[] =
5759 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5760 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
Mike McCormack94fbe092005-09-23 17:21:10 +00005761}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005762
Mike McCormack2586a092005-09-26 09:56:18 +00005763static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5764{
5765 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5766 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5767}
5768
5769static UINT ACTION_BindImage( MSIPACKAGE *package )
5770{
5771 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5772 return msi_unimplemented_action_stub( package, "BindImage", table );
5773}
5774
5775static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5776{
5777 static const WCHAR table[] = {
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005778 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
Mike McCormack2586a092005-09-26 09:56:18 +00005779 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5780}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005781
Mike McCormack2586a092005-09-26 09:56:18 +00005782static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5783{
5784 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5785 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5786}
5787
5788static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5789{
5790 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5791 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5792}
5793
Mike McCormack2586a092005-09-26 09:56:18 +00005794static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5795{
5796 static const WCHAR table[] = {
5797 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5798 return msi_unimplemented_action_stub( package, "DeleteServices", table );
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005799}
Steven Steinee3ac7a2007-02-11 19:51:03 -05005800static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5801{
5802 static const WCHAR table[] = {
5803 'P','r','o','d','u','c','t','I','D',0 };
5804 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5805}
Mike McCormack3b955152005-09-28 18:10:44 +00005806
Mike McCormack3b955152005-09-28 18:10:44 +00005807static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5808{
5809 static const WCHAR table[] = {
5810 'E','n','v','i','r','o','n','m','e','n','t',0 };
5811 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5812}
5813
Mike McCormack3b955152005-09-28 18:10:44 +00005814static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5815{
5816 static const WCHAR table[] = {
5817 'M','s','i','A','s','s','e','m','b','l','y',0 };
5818 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5819}
5820
5821static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5822{
5823 static const WCHAR table[] = { 'F','o','n','t',0 };
5824 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5825}
5826
Mike McCormackf24a9e22005-12-31 13:14:23 +01005827static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5828{
5829 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5830 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5831}
5832
Mike McCormack88603662006-03-22 23:01:56 +09005833static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5834{
5835 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5836 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5837}
5838
5839static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5840{
5841 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5842 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5843}
5844
James Hawkins987c2c82007-05-06 20:52:14 -05005845static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5846{
5847 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5848 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5849}
5850
5851static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5852{
5853 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5854 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5855}
5856
5857static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5858{
5859 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5860 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5861}
5862
5863static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5864{
5865 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5866 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5867}
5868
5869static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5870{
5871 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5872 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5873}
5874
5875static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5876{
5877 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5878 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5879}
5880
5881static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5882{
5883 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5884 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5885}
5886
5887static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5888{
5889 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5890 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5891}
5892
James Hawkins987c2c82007-05-06 20:52:14 -05005893static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5894{
5895 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5896 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5897}
5898
5899static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5900{
5901 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5902 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5903}
5904
5905static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5906{
5907 static const WCHAR table[] = { 'M','I','M','E',0 };
5908 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5909}
5910
5911static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5912{
5913 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5914 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5915}
5916
5917static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5918{
5919 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5920 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5921}
5922
Dmitry Timoshkov1cdf5cd2006-11-29 18:03:14 +08005923static const struct _actions StandardActions[] = {
Mike McCormack55942702005-10-30 19:23:28 +00005924 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
Mike McCormack3b955152005-09-28 18:10:44 +00005925 { szAppSearch, ACTION_AppSearch },
5926 { szBindImage, ACTION_BindImage },
James Hawkins987c2c82007-05-06 20:52:14 -05005927 { szCCPSearch, ACTION_CCPSearch },
Mike McCormack3b955152005-09-28 18:10:44 +00005928 { szCostFinalize, ACTION_CostFinalize },
5929 { szCostInitialize, ACTION_CostInitialize },
5930 { szCreateFolders, ACTION_CreateFolders },
5931 { szCreateShortcuts, ACTION_CreateShortcuts },
5932 { szDeleteServices, ACTION_DeleteServices },
James Hawkins987c2c82007-05-06 20:52:14 -05005933 { szDisableRollback, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005934 { szDuplicateFiles, ACTION_DuplicateFiles },
5935 { szExecuteAction, ACTION_ExecuteAction },
5936 { szFileCost, ACTION_FileCost },
5937 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5938 { szForceReboot, ACTION_ForceReboot },
James Hawkins987c2c82007-05-06 20:52:14 -05005939 { szInstallAdminPackage, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005940 { szInstallExecute, ACTION_InstallExecute },
5941 { szInstallExecuteAgain, ACTION_InstallExecute },
5942 { szInstallFiles, ACTION_InstallFiles},
5943 { szInstallFinalize, ACTION_InstallFinalize },
5944 { szInstallInitialize, ACTION_InstallInitialize },
James Hawkins987c2c82007-05-06 20:52:14 -05005945 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
Mike McCormack3b955152005-09-28 18:10:44 +00005946 { szInstallValidate, ACTION_InstallValidate },
5947 { szIsolateComponents, ACTION_IsolateComponents },
5948 { szLaunchConditions, ACTION_LaunchConditions },
5949 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5950 { szMoveFiles, ACTION_MoveFiles },
5951 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5952 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
James Hawkinsd3bec322006-11-27 18:20:33 -08005953 { szInstallODBC, ACTION_InstallODBC },
Mike McCormack3b955152005-09-28 18:10:44 +00005954 { szInstallServices, ACTION_InstallServices },
5955 { szPatchFiles, ACTION_PatchFiles },
5956 { szProcessComponents, ACTION_ProcessComponents },
5957 { szPublishComponents, ACTION_PublishComponents },
5958 { szPublishFeatures, ACTION_PublishFeatures },
5959 { szPublishProduct, ACTION_PublishProduct },
5960 { szRegisterClassInfo, ACTION_RegisterClassInfo },
Mike McCormack88603662006-03-22 23:01:56 +09005961 { szRegisterComPlus, ACTION_RegisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00005962 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5963 { szRegisterFonts, ACTION_RegisterFonts },
5964 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5965 { szRegisterProduct, ACTION_RegisterProduct },
5966 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5967 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
James Hawkins987c2c82007-05-06 20:52:14 -05005968 { szRegisterUser, ACTION_RegisterUser },
5969 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
Mike McCormack3b955152005-09-28 18:10:44 +00005970 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
James Hawkins987c2c82007-05-06 20:52:14 -05005971 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5972 { szRemoveFiles, ACTION_RemoveFiles },
5973 { szRemoveFolders, ACTION_RemoveFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00005974 { szRemoveIniValues, ACTION_RemoveIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05005975 { szRemoveODBC, ACTION_RemoveODBC },
5976 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5977 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5978 { szResolveSource, ACTION_ResolveSource },
5979 { szRMCCPSearch, ACTION_RMCCPSearch },
5980 { szScheduleReboot, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005981 { szSelfRegModules, ACTION_SelfRegModules },
5982 { szSelfUnregModules, ACTION_SelfUnregModules },
James Hawkins987c2c82007-05-06 20:52:14 -05005983 { szSetODBCFolders, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005984 { szStartServices, ACTION_StartServices },
5985 { szStopServices, ACTION_StopServices },
James Hawkins987c2c82007-05-06 20:52:14 -05005986 { szUnpublishComponents, ACTION_UnpublishComponents },
5987 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5988 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5989 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5990 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
Mike McCormack3b955152005-09-28 18:10:44 +00005991 { szUnregisterFonts, ACTION_UnregisterFonts },
James Hawkins987c2c82007-05-06 20:52:14 -05005992 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5993 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5994 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5995 { szValidateProductID, ACTION_ValidateProductID },
Mike McCormack3b955152005-09-28 18:10:44 +00005996 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5997 { szWriteIniValues, ACTION_WriteIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05005998 { szWriteRegistryValues, ACTION_WriteRegistryValues },
5999 { NULL, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00006000};
Andrew Talbot9e85ec32008-04-03 14:50:28 +01006001
6002static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
6003 UINT* rc, BOOL force )
6004{
6005 BOOL ret = FALSE;
6006 BOOL run = force;
6007 int i;
6008
6009 if (!run && !package->script->CurrentlyScripting)
6010 run = TRUE;
6011
6012 if (!run)
6013 {
6014 if (strcmpW(action,szInstallFinalize) == 0 ||
6015 strcmpW(action,szInstallExecute) == 0 ||
6016 strcmpW(action,szInstallExecuteAgain) == 0)
6017 run = TRUE;
6018 }
6019
6020 i = 0;
6021 while (StandardActions[i].action != NULL)
6022 {
6023 if (strcmpW(StandardActions[i].action, action)==0)
6024 {
6025 if (!run)
6026 {
6027 ui_actioninfo(package, action, TRUE, 0);
6028 *rc = schedule_action(package,INSTALL_SCRIPT,action);
6029 ui_actioninfo(package, action, FALSE, *rc);
6030 }
6031 else
6032 {
6033 ui_actionstart(package, action);
6034 if (StandardActions[i].handler)
6035 {
6036 *rc = StandardActions[i].handler(package);
6037 }
6038 else
6039 {
6040 FIXME("unhandled standard action %s\n",debugstr_w(action));
6041 *rc = ERROR_SUCCESS;
6042 }
6043 }
6044 ret = TRUE;
6045 break;
6046 }
6047 i++;
6048 }
6049 return ret;
6050}