blob: 2efcbbbe0cc9313a96fe2d21b1d40a2be5bf21b3 [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
21/*
Mike McCormack6e2bca32004-07-04 00:25:00 +000022 * Pages I need
Aric Stewart401bd3f2004-06-28 20:34:35 +000023 *
24http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
25
26http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
Aric Stewart401bd3f2004-06-28 20:34:35 +000027 */
28
29#include <stdarg.h>
Aric Stewart401bd3f2004-06-28 20:34:35 +000030
Francois Gouget486d0202004-10-07 03:06:48 +000031#define COBJMACROS
32
Aric Stewart401bd3f2004-06-28 20:34:35 +000033#include "windef.h"
34#include "winbase.h"
35#include "winerror.h"
36#include "winreg.h"
James Hawkins9bc12ad2006-10-19 15:49:54 -070037#include "winsvc.h"
James Hawkinsd3bec322006-11-27 18:20:33 -080038#include "odbcinst.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000039#include "wine/debug.h"
Aric Stewartb6bc6aa2005-02-24 12:47:43 +000040#include "msidefs.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000041#include "msipriv.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000042#include "winuser.h"
43#include "shlobj.h"
44#include "wine/unicode.h"
Steven Edwards98efef12005-04-11 16:10:33 +000045#include "winver.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000046
Aric Stewartbd1bbc12005-01-03 20:00:13 +000047#define REG_PROGRESS_VALUE 13200
48#define COMPONENT_PROGRESS_VALUE 24000
Aric Stewart401bd3f2004-06-28 20:34:35 +000049
Aric Stewart401bd3f2004-06-28 20:34:35 +000050WINE_DEFAULT_DEBUG_CHANNEL(msi);
51
52/*
53 * Prototypes
54 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +000055static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
56static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
Aric Stewartf8f64402005-03-24 19:03:45 +000057static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
Aric Stewart90c57392005-01-31 16:23:12 +000058
Aric Stewart401bd3f2004-06-28 20:34:35 +000059/*
60 * consts and values used
61 */
Juan Lang014ad3b2005-03-01 10:41:52 +000062static const WCHAR c_colon[] = {'C',':','\\',0};
Aric Stewartc6689522005-06-17 20:56:55 +000063
Mike McCormack9ba8ba32005-10-30 19:04:26 +000064static const WCHAR szCreateFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000065 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000066static const WCHAR szCostFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000067 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
Aric Stewartc6689522005-06-17 20:56:55 +000068const WCHAR szInstallFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000069 {'I','n','s','t','a','l','l','F','i','l','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +000070const WCHAR szDuplicateFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000071 {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000072static const WCHAR szWriteRegistryValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000073 {'W','r','i','t','e','R','e','g','i','s','t','r','y',
74 'V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000075static const WCHAR szCostInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000076 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000077static const WCHAR szFileCost[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000078 {'F','i','l','e','C','o','s','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000079static const WCHAR szInstallInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000080 {'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 +000081static const WCHAR szInstallValidate[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000082 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000083static const WCHAR szLaunchConditions[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000084 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000085static const WCHAR szProcessComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000086 {'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 +000087static const WCHAR szRegisterTypeLibraries[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000088 {'R','e','g','i','s','t','e','r','T','y','p','e',
89 'L','i','b','r','a','r','i','e','s',0};
Aric Stewartdb982e22005-06-16 15:51:44 +000090const WCHAR szRegisterClassInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000091 {'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 +000092const WCHAR szRegisterProgIdInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000093 {'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 +000094static const WCHAR szCreateShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000095 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000096static const WCHAR szPublishProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000097 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000098static const WCHAR szWriteIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000099 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000100static const WCHAR szSelfRegModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000101 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000102static const WCHAR szPublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000103 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000104static const WCHAR szRegisterProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000105 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000106static const WCHAR szInstallExecute[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000107 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000108static const WCHAR szInstallExecuteAgain[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000109 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
110 'A','g','a','i','n',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000111static const WCHAR szInstallFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000112 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000113static const WCHAR szForceReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000114 {'F','o','r','c','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000115static const WCHAR szResolveSource[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000116 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
Alexandre Julliardb79a53e2006-06-12 13:39:59 +0200117static const WCHAR szAppSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000118 {'A','p','p','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000119static const WCHAR szAllocateRegistrySpace[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000120 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
121 'S','p','a','c','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000122static const WCHAR szBindImage[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000123 {'B','i','n','d','I','m','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000124static const WCHAR szCCPSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000125 {'C','C','P','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000126static const WCHAR szDeleteServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000127 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000128static const WCHAR szDisableRollback[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000129 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000130static const WCHAR szExecuteAction[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000131 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
Aric Stewartdb982e22005-06-16 15:51:44 +0000132const WCHAR szFindRelatedProducts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000133 {'F','i','n','d','R','e','l','a','t','e','d',
134 'P','r','o','d','u','c','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000135static const WCHAR szInstallAdminPackage[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000136 {'I','n','s','t','a','l','l','A','d','m','i','n',
137 'P','a','c','k','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000138static const WCHAR szInstallSFPCatalogFile[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000139 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
140 'F','i','l','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000141static const WCHAR szIsolateComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000142 {'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 +0000143const WCHAR szMigrateFeatureStates[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000144 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
145 'S','t','a','t','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000146const WCHAR szMoveFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000147 {'M','o','v','e','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000148static const WCHAR szMsiPublishAssemblies[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000149 {'M','s','i','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 szMsiUnpublishAssemblies[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000152 {'M','s','i','U','n','p','u','b','l','i','s','h',
153 'A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000154static const WCHAR szInstallODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000155 {'I','n','s','t','a','l','l','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000156static const WCHAR szInstallServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000157 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000158const WCHAR szPatchFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000159 {'P','a','t','c','h','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000160static const WCHAR szPublishComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000161 {'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 +0000162static const WCHAR szRegisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000163 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Aric Stewartdb982e22005-06-16 15:51:44 +0000164const WCHAR szRegisterExtensionInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000165 {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
166 'I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000167static const WCHAR szRegisterFonts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000168 {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
Aric Stewartdb982e22005-06-16 15:51:44 +0000169const WCHAR szRegisterMIMEInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000170 {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000171static const WCHAR szRegisterUser[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000172 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000173const WCHAR szRemoveDuplicateFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000174 {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
175 'F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000176static const WCHAR szRemoveEnvironmentStrings[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000177 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
178 'S','t','r','i','n','g','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000179const WCHAR szRemoveExistingProducts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000180 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
181 'P','r','o','d','u','c','t','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000182const WCHAR szRemoveFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000183 {'R','e','m','o','v','e','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000184static const WCHAR szRemoveFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000185 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000186static const WCHAR szRemoveIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000187 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000188static const WCHAR szRemoveODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000189 {'R','e','m','o','v','e','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000190static const WCHAR szRemoveRegistryValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000191 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
192 'V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000193static const WCHAR szRemoveShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000194 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000195static const WCHAR szRMCCPSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000196 {'R','M','C','C','P','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000197static const WCHAR szScheduleReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000198 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000199static const WCHAR szSelfUnregModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000200 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000201static const WCHAR szSetODBCFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000202 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000203static const WCHAR szStartServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000204 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000205static const WCHAR szStopServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000206 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000207static const WCHAR szUnpublishComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000208 {'U','n','p','u','b','l','i','s','h',
209 'C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000210static const WCHAR szUnpublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000211 {'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 +0000212const WCHAR szUnregisterClassInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000213 {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
214 'I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000215static const WCHAR szUnregisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000216 {'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 +0000217const WCHAR szUnregisterExtensionInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000218 {'U','n','r','e','g','i','s','t','e','r',
219 'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000220static const WCHAR szUnregisterFonts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000221 {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
Aric Stewartc6689522005-06-17 20:56:55 +0000222const WCHAR szUnregisterMIMEInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000223 {'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 +0000224const WCHAR szUnregisterProgIdInfo[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000225 {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
226 'I','n','f','o',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000227static const WCHAR szUnregisterTypeLibraries[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000228 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
229 'L','i','b','r','a','r','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000230static const WCHAR szValidateProductID[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000231 {'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 +0000232static const WCHAR szWriteEnvironmentStrings[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000233 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
234 'S','t','r','i','n','g','s',0};
Aric Stewart90c57392005-01-31 16:23:12 +0000235
Mike McCormack3b955152005-09-28 18:10:44 +0000236/* action handlers */
237typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
238
Aric Stewart90c57392005-01-31 16:23:12 +0000239struct _actions {
240 LPCWSTR action;
241 STANDARDACTIONHANDLER handler;
242};
243
Dmitry Timoshkov1cdf5cd2006-11-29 18:03:14 +0800244static const struct _actions StandardActions[];
Aric Stewart90c57392005-01-31 16:23:12 +0000245
Aric Stewart2703d712005-06-20 15:33:10 +0000246
247/********************************************************
248 * helper functions
249 ********************************************************/
250
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000251static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
Aric Stewartd2c395a2004-07-06 18:48:15 +0000252{
Aric Stewartd2c395a2004-07-06 18:48:15 +0000253 static const WCHAR Query_t[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000254 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000255 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
256 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
257 ' ','\'','%','s','\'',0};
Robert Shearmand679bc52006-01-23 17:30:31 +0100258 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000259
Mike McCormack0b352c72005-06-02 10:29:57 +0000260 row = MSI_QueryGetRecord( package->db, Query_t, action );
261 if (!row)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000262 return;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000263 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
264 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000265}
266
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000267static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
Aric Stewartd2c395a2004-07-06 18:48:15 +0000268 UINT rc)
269{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000270 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000271 static const WCHAR template_s[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000272 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
273 '%','s', '.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000274 static const WCHAR template_e[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000275 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
276 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
277 '%','i','.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000278 static const WCHAR format[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000279 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000280 WCHAR message[1024];
281 WCHAR timet[0x100];
282
283 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
284 if (start)
285 sprintfW(message,template_s,timet,action);
286 else
287 sprintfW(message,template_e,timet,action,rc);
288
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000289 row = MSI_CreateRecord(1);
290 MSI_RecordSetStringW(row,1,message);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000291
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000292 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
293 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000294}
295
James Hawkinsdc3060c2007-07-16 14:45:29 -0700296UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
Mike McCormacke3452222005-09-28 15:12:32 +0000297{
298 LPCWSTR ptr,ptr2;
299 BOOL quote;
300 DWORD len;
301 LPWSTR prop = NULL, val = NULL;
302
303 if (!szCommandLine)
304 return ERROR_SUCCESS;
305
306 ptr = szCommandLine;
307
308 while (*ptr)
309 {
310 if (*ptr==' ')
311 {
312 ptr++;
313 continue;
314 }
315
316 TRACE("Looking at %s\n",debugstr_w(ptr));
317
318 ptr2 = strchrW(ptr,'=');
319 if (!ptr2)
320 {
321 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
322 break;
323 }
324
325 quote = FALSE;
326
327 len = ptr2-ptr;
328 prop = msi_alloc((len+1)*sizeof(WCHAR));
329 memcpy(prop,ptr,len*sizeof(WCHAR));
330 prop[len]=0;
331 ptr2++;
332
333 len = 0;
334 ptr = ptr2;
335 while (*ptr && (quote || (!quote && *ptr!=' ')))
336 {
337 if (*ptr == '"')
338 quote = !quote;
339 ptr++;
340 len++;
341 }
342
343 if (*ptr2=='"')
344 {
345 ptr2++;
346 len -= 2;
347 }
348 val = msi_alloc((len+1)*sizeof(WCHAR));
349 memcpy(val,ptr2,len*sizeof(WCHAR));
350 val[len] = 0;
351
352 if (lstrlenW(prop) > 0)
353 {
354 TRACE("Found commandline property (%s) = (%s)\n",
355 debugstr_w(prop), debugstr_w(val));
356 MSI_SetPropertyW(package,prop,val);
357 }
358 msi_free(val);
359 msi_free(prop);
360 }
361
362 return ERROR_SUCCESS;
363}
364
Mike McCormack965a72a2005-10-26 12:06:21 +0000365
366static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
367{
Andrew Talbot2e372c02006-09-17 08:52:49 +0100368 LPCWSTR pc;
Mike McCormack965a72a2005-10-26 12:06:21 +0000369 LPWSTR p, *ret = NULL;
370 UINT count = 0;
371
372 if (!str)
373 return ret;
374
375 /* count the number of substrings */
Andrew Talbot2e372c02006-09-17 08:52:49 +0100376 for ( pc = str, count = 0; pc; count++ )
Mike McCormack965a72a2005-10-26 12:06:21 +0000377 {
Andrew Talbot2e372c02006-09-17 08:52:49 +0100378 pc = strchrW( pc, sep );
379 if (pc)
380 pc++;
Mike McCormack965a72a2005-10-26 12:06:21 +0000381 }
382
383 /* allocate space for an array of substring pointers and the substrings */
384 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
385 (lstrlenW(str)+1) * sizeof(WCHAR) );
386 if (!ret)
387 return ret;
388
389 /* copy the string and set the pointers */
390 p = (LPWSTR) &ret[count+1];
391 lstrcpyW( p, str );
392 for( count = 0; (ret[count] = p); count++ )
393 {
394 p = strchrW( p, sep );
395 if (p)
396 *p++ = 0;
397 }
398
399 return ret;
400}
401
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900402static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
403{
404 WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
405 LPWSTR prod_code, patch_product;
406 UINT ret;
407
408 prod_code = msi_dup_property( package, szProductCode );
409 patch_product = msi_get_suminfo_product( patch );
410
411 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
412
413 if ( strstrW( patch_product, prod_code ) )
414 ret = ERROR_SUCCESS;
415 else
416 ret = ERROR_FUNCTION_FAILED;
417
418 msi_free( patch_product );
419 msi_free( prod_code );
420
421 return ret;
422}
423
Mike McCormack965a72a2005-10-26 12:06:21 +0000424static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
425 MSIDATABASE *patch_db, LPCWSTR name )
426{
427 UINT ret = ERROR_FUNCTION_FAILED;
428 IStorage *stg = NULL;
429 HRESULT r;
430
431 TRACE("%p %s\n", package, debugstr_w(name) );
432
433 if (*name++ != ':')
434 {
435 ERR("expected a colon in %s\n", debugstr_w(name));
436 return ERROR_FUNCTION_FAILED;
437 }
438
439 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
440 if (SUCCEEDED(r))
441 {
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900442 ret = msi_check_transform_applicable( package, stg );
443 if (ret == ERROR_SUCCESS)
444 msi_table_apply_transform( package->db, stg );
445 else
446 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
Mike McCormack965a72a2005-10-26 12:06:21 +0000447 IStorage_Release( stg );
Mike McCormack965a72a2005-10-26 12:06:21 +0000448 }
449 else
450 ERR("failed to open substorage %s\n", debugstr_w(name));
451
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900452 return ERROR_SUCCESS;
Mike McCormack965a72a2005-10-26 12:06:21 +0000453}
454
455static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
456{
James Hawkins261e1172007-06-15 14:12:13 -0700457 static const WCHAR szProdCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
458 LPWSTR guid_list, *guids, product_code;
Mike McCormack965a72a2005-10-26 12:06:21 +0000459 UINT i, ret = ERROR_FUNCTION_FAILED;
460
James Hawkins261e1172007-06-15 14:12:13 -0700461 product_code = msi_dup_property( package, szProdCode );
462 if (!product_code)
Mike McCormack965a72a2005-10-26 12:06:21 +0000463 {
James Hawkins261e1172007-06-15 14:12:13 -0700464 /* FIXME: the property ProductCode should be written into the DB somewhere */
465 ERR("no product code to check\n");
Mike McCormack965a72a2005-10-26 12:06:21 +0000466 return ERROR_SUCCESS;
467 }
468
469 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
470 guids = msi_split_string( guid_list, ';' );
471 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
472 {
James Hawkins261e1172007-06-15 14:12:13 -0700473 if (!lstrcmpW( guids[i], product_code ))
Mike McCormack965a72a2005-10-26 12:06:21 +0000474 ret = ERROR_SUCCESS;
475 }
476 msi_free( guids );
477 msi_free( guid_list );
James Hawkins261e1172007-06-15 14:12:13 -0700478 msi_free( product_code );
Mike McCormack965a72a2005-10-26 12:06:21 +0000479
480 return ret;
481}
482
483static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
484{
485 MSISUMMARYINFO *si;
486 LPWSTR str, *substorage;
487 UINT i, r = ERROR_SUCCESS;
488
Mike McCormack7f98f1d2006-10-24 01:11:30 +0900489 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
Mike McCormack965a72a2005-10-26 12:06:21 +0000490 if (!si)
491 return ERROR_FUNCTION_FAILED;
492
493 msi_check_patch_applicable( package, si );
494
495 /* enumerate the substorage */
496 str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
497 substorage = msi_split_string( str, ';' );
498 for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
499 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
500 msi_free( substorage );
501 msi_free( str );
502
503 /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
504
505 msiobj_release( &si->hdr );
506
507 return r;
508}
509
510static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
511{
512 MSIDATABASE *patch_db = NULL;
513 UINT r;
514
515 TRACE("%p %s\n", package, debugstr_w( file ) );
516
517 /* FIXME:
518 * We probably want to make sure we only open a patch collection here.
519 * Patch collections (.msp) and databases (.msi) have different GUIDs
520 * but currently MSI_OpenDatabaseW will accept both.
521 */
522 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
523 if ( r != ERROR_SUCCESS )
524 {
525 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
526 return r;
527 }
528
529 msi_parse_patch_summary( package, patch_db );
Mike McCormack9a4ba8c2006-11-01 15:09:23 +0900530
531 /*
532 * There might be a CAB file in the patch package,
533 * so append it to the list of storage to search for streams.
534 */
535 append_storage_to_db( package->db, patch_db->storage );
536
Mike McCormack965a72a2005-10-26 12:06:21 +0000537 msiobj_release( &patch_db->hdr );
538
539 return ERROR_SUCCESS;
540}
541
542/* get the PATCH property, and apply all the patches it specifies */
543static UINT msi_apply_patches( MSIPACKAGE *package )
544{
545 static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
546 LPWSTR patch_list, *patches;
547 UINT i, r = ERROR_SUCCESS;
548
549 patch_list = msi_dup_property( package, szPatch );
550
551 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
552
553 patches = msi_split_string( patch_list, ';' );
554 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
555 r = msi_apply_patch_package( package, patches[i] );
556
557 msi_free( patches );
558 msi_free( patch_list );
559
560 return r;
561}
562
Mike McCormacke534e772006-01-04 14:51:25 +0100563static UINT msi_apply_transforms( MSIPACKAGE *package )
564{
565 static const WCHAR szTransforms[] = {
566 'T','R','A','N','S','F','O','R','M','S',0 };
567 LPWSTR xform_list, *xforms;
568 UINT i, r = ERROR_SUCCESS;
569
570 xform_list = msi_dup_property( package, szTransforms );
571 xforms = msi_split_string( xform_list, ';' );
572
573 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
574 {
575 if (xforms[i][0] == ':')
576 r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
577 else
578 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
579 }
580
581 msi_free( xforms );
582 msi_free( xform_list );
583
584 return r;
585}
586
James Hawkins6da80412007-04-15 03:10:58 -0500587BOOL ui_sequence_exists( MSIPACKAGE *package )
588{
589 MSIQUERY *view;
590 UINT rc;
591
592 static const WCHAR ExecSeqQuery [] =
593 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
594 '`','I','n','s','t','a','l','l',
595 'U','I','S','e','q','u','e','n','c','e','`',
596 ' ','W','H','E','R','E',' ',
597 '`','S','e','q','u','e','n','c','e','`',' ',
598 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
599 '`','S','e','q','u','e','n','c','e','`',0};
600
601 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
602 if (rc == ERROR_SUCCESS)
603 {
604 msiobj_release(&view->hdr);
605 return TRUE;
606 }
607
608 return FALSE;
609}
610
James Hawkinsc777d302008-01-05 13:45:13 -0700611static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
612{
James Hawkins062070b2008-01-05 13:46:39 -0700613 LPWSTR p, db;
James Hawkinsc777d302008-01-05 13:45:13 -0700614 LPWSTR source, check;
615 DWORD len;
616
James Hawkinsc37849a2008-01-05 13:50:59 -0700617 static const WCHAR szOriginalDatabase[] =
618 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
619
James Hawkins062070b2008-01-05 13:46:39 -0700620 db = msi_dup_property( package, szOriginalDatabase );
621 if (!db)
622 return ERROR_OUTOFMEMORY;
James Hawkinsc777d302008-01-05 13:45:13 -0700623
James Hawkins062070b2008-01-05 13:46:39 -0700624 p = strrchrW( db, '\\' );
625 if (!p)
626 {
James Hawkins18648762008-01-05 13:47:14 -0700627 p = strrchrW( db, '/' );
628 if (!p)
629 {
630 msi_free(db);
631 return ERROR_SUCCESS;
632 }
James Hawkins062070b2008-01-05 13:46:39 -0700633 }
634
635 len = p - db + 2;
James Hawkinsc777d302008-01-05 13:45:13 -0700636 source = msi_alloc( len * sizeof(WCHAR) );
James Hawkins062070b2008-01-05 13:46:39 -0700637 lstrcpynW( source, db, len );
James Hawkinsc777d302008-01-05 13:45:13 -0700638
639 check = msi_dup_property( package, cszSourceDir );
640 if (!check || replace)
641 MSI_SetPropertyW( package, cszSourceDir, source );
642
643 msi_free( check );
644
645 check = msi_dup_property( package, cszSOURCEDIR );
646 if (!check || replace)
647 MSI_SetPropertyW( package, cszSOURCEDIR, source );
648
649 msi_free( check );
650 msi_free( source );
James Hawkins062070b2008-01-05 13:46:39 -0700651 msi_free( db );
James Hawkinsc777d302008-01-05 13:45:13 -0700652
653 return ERROR_SUCCESS;
654}
655
Aric Stewart401bd3f2004-06-28 20:34:35 +0000656/****************************************************
657 * TOP level entry points
658 *****************************************************/
659
Mike McCormack61f24a42005-09-30 10:32:41 +0000660UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
661 LPCWSTR szCommandLine )
Aric Stewart401bd3f2004-06-28 20:34:35 +0000662{
Aric Stewart401bd3f2004-06-28 20:34:35 +0000663 UINT rc;
James Hawkins6da80412007-04-15 03:10:58 -0500664 BOOL ui = FALSE, ui_exists;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000665 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
Aric Stewart6269f002005-01-17 13:40:39 +0000666 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
667 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
668
669 MSI_SetPropertyW(package, szAction, szInstall);
Aric Stewart9cd707d2005-05-27 19:24:22 +0000670
Mike McCormack3a940112006-04-19 02:29:03 +0900671 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
Aric Stewart401bd3f2004-06-28 20:34:35 +0000672
Aric Stewartc9802932005-06-30 20:45:43 +0000673 package->script->InWhatSequence = SEQUENCE_INSTALL;
674
Aric Stewarte95136b2004-06-29 03:44:01 +0000675 if (szPackagePath)
676 {
James Hawkinsc777d302008-01-05 13:45:13 -0700677 LPWSTR p, dir;
Andrew Talbot0e14c292007-07-23 18:53:19 +0100678 LPCWSTR file;
James Hawkins08443b32007-07-02 20:19:46 -0700679
680 dir = strdupW(szPackagePath);
681 p = strrchrW(dir, '\\');
Aric Stewarte95136b2004-06-29 03:44:01 +0000682 if (p)
Andrew Talbot0e14c292007-07-23 18:53:19 +0100683 {
James Hawkins08443b32007-07-02 20:19:46 -0700684 *(++p) = 0;
Andrew Talbot0e14c292007-07-23 18:53:19 +0100685 file = szPackagePath + (p - dir);
686 }
Aric Stewartc1e5c4a2005-02-08 14:26:49 +0000687 else
688 {
James Hawkins08443b32007-07-02 20:19:46 -0700689 msi_free(dir);
690 dir = msi_alloc(MAX_PATH*sizeof(WCHAR));
691 GetCurrentDirectoryW(MAX_PATH, dir);
692 lstrcatW(dir, cszbs);
Andrew Talbot0e14c292007-07-23 18:53:19 +0100693 file = szPackagePath;
Aric Stewartc1e5c4a2005-02-08 14:26:49 +0000694 }
Aric Stewarte95136b2004-06-29 03:44:01 +0000695
James Hawkins08443b32007-07-02 20:19:46 -0700696 msi_free( package->PackagePath );
Andrew Talbot0e14c292007-07-23 18:53:19 +0100697 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
James Hawkins08443b32007-07-02 20:19:46 -0700698 if (!package->PackagePath)
699 {
700 msi_free(dir);
701 return ERROR_OUTOFMEMORY;
702 }
703
704 lstrcpyW(package->PackagePath, dir);
Andrew Talbot0e14c292007-07-23 18:53:19 +0100705 lstrcatW(package->PackagePath, file);
James Hawkins08443b32007-07-02 20:19:46 -0700706 msi_free(dir);
James Hawkinsc777d302008-01-05 13:45:13 -0700707
708 msi_set_sourcedir_props(package, FALSE);
Aric Stewarte95136b2004-06-29 03:44:01 +0000709 }
Aric Stewart401bd3f2004-06-28 20:34:35 +0000710
Mike McCormacke3452222005-09-28 15:12:32 +0000711 msi_parse_command_line( package, szCommandLine );
Mike McCormack74f0de92005-09-29 10:32:39 +0000712
Mike McCormacke534e772006-01-04 14:51:25 +0100713 msi_apply_transforms( package );
Mike McCormack965a72a2005-10-26 12:06:21 +0000714 msi_apply_patches( package );
715
James Hawkins30fc5602007-07-12 11:36:43 -0700716 /* properties may have been added by a transform */
717 msi_clone_properties( package );
718
Misha Koshelevd8b00a02007-02-06 23:53:24 -0600719 if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED )
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000720 {
Mike McCormack74f0de92005-09-29 10:32:39 +0000721 package->script->InWhatSequence |= SEQUENCE_UI;
722 rc = ACTION_ProcessUISequence(package);
723 ui = TRUE;
James Hawkins6da80412007-04-15 03:10:58 -0500724 ui_exists = ui_sequence_exists(package);
725 if (rc == ERROR_SUCCESS || !ui_exists)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000726 {
Mike McCormack74f0de92005-09-29 10:32:39 +0000727 package->script->InWhatSequence |= SEQUENCE_EXEC;
James Hawkins6da80412007-04-15 03:10:58 -0500728 rc = ACTION_ProcessExecSequence(package,ui_exists);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000729 }
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000730 }
731 else
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000732 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000733
Aric Stewart9cd707d2005-05-27 19:24:22 +0000734 package->script->CurrentlyScripting= FALSE;
735
Aric Stewart09d35c32004-12-27 19:00:26 +0000736 /* process the ending type action */
737 if (rc == ERROR_SUCCESS)
Aric Stewartf8f64402005-03-24 19:03:45 +0000738 ACTION_PerformActionSequence(package,-1,ui);
Aric Stewart6b16f292005-01-27 11:12:56 +0000739 else if (rc == ERROR_INSTALL_USEREXIT)
Aric Stewartf8f64402005-03-24 19:03:45 +0000740 ACTION_PerformActionSequence(package,-2,ui);
Aric Stewart6b16f292005-01-27 11:12:56 +0000741 else if (rc == ERROR_INSTALL_SUSPEND)
Aric Stewartf8f64402005-03-24 19:03:45 +0000742 ACTION_PerformActionSequence(package,-4,ui);
Aric Stewart9cd707d2005-05-27 19:24:22 +0000743 else /* failed */
744 ACTION_PerformActionSequence(package,-3,ui);
Aric Stewart54c67dd2005-01-25 20:17:09 +0000745
746 /* finish up running custom actions */
747 ACTION_FinishCustomActions(package);
Aric Stewart09d35c32004-12-27 19:00:26 +0000748
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000749 return rc;
750}
751
Aric Stewartf8f64402005-03-24 19:03:45 +0000752static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
Aric Stewart09d35c32004-12-27 19:00:26 +0000753{
Mike McCormack0b352c72005-06-02 10:29:57 +0000754 UINT rc = ERROR_SUCCESS;
Aric Stewart09d35c32004-12-27 19:00:26 +0000755 MSIRECORD * row = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +0000756 static const WCHAR ExecSeqQuery[] =
757 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000758 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
759 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
760 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
Aric Stewart09d35c32004-12-27 19:00:26 +0000761
Aric Stewartf8f64402005-03-24 19:03:45 +0000762 static const WCHAR UISeqQuery[] =
763 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000764 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
765 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
Aric Stewartf8f64402005-03-24 19:03:45 +0000766 ' ', '=',' ','%','i',0};
767
768 if (UI)
Mike McCormack0b352c72005-06-02 10:29:57 +0000769 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
Aric Stewartf8f64402005-03-24 19:03:45 +0000770 else
Mike McCormack0b352c72005-06-02 10:29:57 +0000771 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
Aric Stewart09d35c32004-12-27 19:00:26 +0000772
Mike McCormack0b352c72005-06-02 10:29:57 +0000773 if (row)
Aric Stewart09d35c32004-12-27 19:00:26 +0000774 {
Mike McCormack20806c72005-06-07 21:34:05 +0000775 LPCWSTR action, cond;
776
Aric Stewart09d35c32004-12-27 19:00:26 +0000777 TRACE("Running the actions\n");
778
Aric Stewart09d35c32004-12-27 19:00:26 +0000779 /* check conditions */
Mike McCormack20806c72005-06-07 21:34:05 +0000780 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900781
782 /* this is a hack to skip errors in the condition code */
783 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
784 goto end;
Aric Stewart09d35c32004-12-27 19:00:26 +0000785
Mike McCormack20806c72005-06-07 21:34:05 +0000786 action = MSI_RecordGetString(row,1);
787 if (!action)
Aric Stewart09d35c32004-12-27 19:00:26 +0000788 {
Mike McCormack20806c72005-06-07 21:34:05 +0000789 ERR("failed to fetch action\n");
790 rc = ERROR_FUNCTION_FAILED;
Aric Stewart09d35c32004-12-27 19:00:26 +0000791 goto end;
792 }
793
Aric Stewartf8f64402005-03-24 19:03:45 +0000794 if (UI)
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100795 rc = ACTION_PerformUIAction(package,action,-1);
Aric Stewartf8f64402005-03-24 19:03:45 +0000796 else
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100797 rc = ACTION_PerformAction(package,action,-1,FALSE);
Aric Stewart09d35c32004-12-27 19:00:26 +0000798end:
Mike McCormack0b352c72005-06-02 10:29:57 +0000799 msiobj_release(&row->hdr);
Aric Stewart09d35c32004-12-27 19:00:26 +0000800 }
801 else
802 rc = ERROR_SUCCESS;
803
804 return rc;
805}
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000806
Aric Stewart2703d712005-06-20 15:33:10 +0000807typedef struct {
808 MSIPACKAGE* package;
809 BOOL UI;
810} iterate_action_param;
811
812static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
813{
814 iterate_action_param *iap= (iterate_action_param*)param;
815 UINT rc;
816 LPCWSTR cond, action;
817
818 action = MSI_RecordGetString(row,1);
819 if (!action)
820 {
821 ERR("Error is retrieving action name\n");
Mike McCormack9375fd92006-10-27 17:29:02 +0900822 return ERROR_FUNCTION_FAILED;
Aric Stewart2703d712005-06-20 15:33:10 +0000823 }
824
825 /* check conditions */
826 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900827
828 /* this is a hack to skip errors in the condition code */
829 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
Aric Stewart2703d712005-06-20 15:33:10 +0000830 {
Mike McCormack9375fd92006-10-27 17:29:02 +0900831 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
832 return ERROR_SUCCESS;
Aric Stewart2703d712005-06-20 15:33:10 +0000833 }
834
835 if (iap->UI)
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100836 rc = ACTION_PerformUIAction(iap->package,action,-1);
Aric Stewart2703d712005-06-20 15:33:10 +0000837 else
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100838 rc = ACTION_PerformAction(iap->package,action,-1,FALSE);
Aric Stewart2703d712005-06-20 15:33:10 +0000839
Mike McCormack4f634a32005-07-06 15:44:51 +0000840 msi_dialog_check_messages( NULL );
841
842 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
843 rc = iap->package->CurrentInstallState;
844
Aric Stewart2703d712005-06-20 15:33:10 +0000845 if (rc == ERROR_FUNCTION_NOT_CALLED)
846 rc = ERROR_SUCCESS;
847
848 if (rc != ERROR_SUCCESS)
Mike McCormack558abec2005-10-27 12:39:28 +0000849 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
Aric Stewart2703d712005-06-20 15:33:10 +0000850
851 return rc;
852}
853
Mike McCormackd34b1c22005-09-21 10:55:23 +0000854UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
855{
856 MSIQUERY * view;
857 UINT r;
858 static const WCHAR query[] =
859 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
860 '`','%','s','`',
861 ' ','W','H','E','R','E',' ',
862 '`','S','e','q','u','e','n','c','e','`',' ',
863 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
864 '`','S','e','q','u','e','n','c','e','`',0};
865 iterate_action_param iap;
866
867 /*
868 * FIXME: probably should be checking UILevel in the
869 * ACTION_PerformUIAction/ACTION_PerformAction
870 * rather than saving the UI level here. Those
871 * two functions can be merged too.
872 */
873 iap.package = package;
874 iap.UI = TRUE;
875
876 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
877
878 r = MSI_OpenQuery( package->db, &view, query, szTable );
879 if (r == ERROR_SUCCESS)
880 {
881 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
882 msiobj_release(&view->hdr);
883 }
884
885 return r;
886}
887
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000888static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000889{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000890 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000891 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000892 static const WCHAR ExecSeqQuery[] =
893 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000894 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
895 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
896 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000897 'O','R','D','E','R',' ', 'B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000898 '`','S','e','q','u','e','n','c','e','`',0 };
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000899 MSIRECORD * row = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +0000900 static const WCHAR IVQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +0000901 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
902 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
903 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
904 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
905 ' ','\'', 'I','n','s','t','a','l','l',
906 'V','a','l','i','d','a','t','e','\'', 0};
Mike McCormack9db0e072004-12-22 15:05:07 +0000907 INT seq = 0;
Aric Stewart2703d712005-06-20 15:33:10 +0000908 iterate_action_param iap;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000909
Aric Stewart2703d712005-06-20 15:33:10 +0000910 iap.package = package;
911 iap.UI = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000912
Aric Stewart9cd707d2005-05-27 19:24:22 +0000913 if (package->script->ExecuteSequenceRun)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000914 {
915 TRACE("Execute Sequence already Run\n");
916 return ERROR_SUCCESS;
917 }
918
Aric Stewart9cd707d2005-05-27 19:24:22 +0000919 package->script->ExecuteSequenceRun = TRUE;
Aric Stewart2703d712005-06-20 15:33:10 +0000920
Mike McCormack9db0e072004-12-22 15:05:07 +0000921 /* get the sequence number */
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000922 if (UIran)
923 {
Mike McCormack0b352c72005-06-02 10:29:57 +0000924 row = MSI_QueryGetRecord(package->db, IVQuery);
925 if( !row )
926 return ERROR_FUNCTION_FAILED;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000927 seq = MSI_RecordGetInteger(row,1);
928 msiobj_release(&row->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000929 }
Mike McCormack9db0e072004-12-22 15:05:07 +0000930
Mike McCormack0c238852005-01-21 16:19:11 +0000931 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000932 if (rc == ERROR_SUCCESS)
933 {
Aric Stewart2703d712005-06-20 15:33:10 +0000934 TRACE("Running the actions\n");
Aric Stewart401bd3f2004-06-28 20:34:35 +0000935
Aric Stewart2703d712005-06-20 15:33:10 +0000936 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000937 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000938 }
939
Aric Stewart401bd3f2004-06-28 20:34:35 +0000940 return rc;
941}
942
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000943static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000944{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000945 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000946 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000947 static const WCHAR ExecSeqQuery [] =
948 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000949 '`','I','n','s','t','a','l','l',
950 'U','I','S','e','q','u','e','n','c','e','`',
951 ' ','W','H','E','R','E',' ',
952 '`','S','e','q','u','e','n','c','e','`',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000953 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000954 '`','S','e','q','u','e','n','c','e','`',0};
Aric Stewart2703d712005-06-20 15:33:10 +0000955 iterate_action_param iap;
956
957 iap.package = package;
958 iap.UI = TRUE;
959
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000960 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000961
962 if (rc == ERROR_SUCCESS)
963 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000964 TRACE("Running the actions\n");
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000965
Aric Stewart2703d712005-06-20 15:33:10 +0000966 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000967 msiobj_release(&view->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000968 }
969
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000970 return rc;
971}
972
Aric Stewart401bd3f2004-06-28 20:34:35 +0000973/********************************************************
974 * ACTION helper functions and functions that perform the actions
975 *******************************************************/
Aric Stewart9cd707d2005-05-27 19:24:22 +0000976static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
977 UINT* rc, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +0000978{
979 BOOL ret = FALSE;
Aric Stewart9cd707d2005-05-27 19:24:22 +0000980 BOOL run = force;
Aric Stewart3f318602005-02-01 18:46:26 +0000981 int i;
Aric Stewart9cd707d2005-05-27 19:24:22 +0000982
983 if (!run && !package->script->CurrentlyScripting)
984 run = TRUE;
985
986 if (!run)
987 {
988 if (strcmpW(action,szInstallFinalize) == 0 ||
989 strcmpW(action,szInstallExecute) == 0 ||
990 strcmpW(action,szInstallExecuteAgain) == 0)
991 run = TRUE;
992 }
993
Aric Stewart3f318602005-02-01 18:46:26 +0000994 i = 0;
995 while (StandardActions[i].action != NULL)
996 {
997 if (strcmpW(StandardActions[i].action, action)==0)
998 {
Aric Stewart9cd707d2005-05-27 19:24:22 +0000999 if (!run)
Aric Stewartd6ecf582005-02-02 09:29:30 +00001000 {
Aric Stewart9cd707d2005-05-27 19:24:22 +00001001 ui_actioninfo(package, action, TRUE, 0);
1002 *rc = schedule_action(package,INSTALL_SCRIPT,action);
1003 ui_actioninfo(package, action, FALSE, *rc);
Aric Stewartd6ecf582005-02-02 09:29:30 +00001004 }
1005 else
1006 {
Aric Stewart9cd707d2005-05-27 19:24:22 +00001007 ui_actionstart(package, action);
1008 if (StandardActions[i].handler)
1009 {
1010 *rc = StandardActions[i].handler(package);
1011 }
1012 else
1013 {
Mike McCormack54a28912005-09-06 09:23:18 +00001014 FIXME("unhandled standard action %s\n",debugstr_w(action));
Aric Stewart9cd707d2005-05-27 19:24:22 +00001015 *rc = ERROR_SUCCESS;
1016 }
Aric Stewartd6ecf582005-02-02 09:29:30 +00001017 }
Aric Stewart3f318602005-02-01 18:46:26 +00001018 ret = TRUE;
1019 break;
1020 }
1021 i++;
1022 }
1023 return ret;
1024}
1025
Mike McCormackf9acfe62005-06-07 20:29:51 +00001026static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001027 UINT* rc, UINT script, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +00001028{
1029 BOOL ret=FALSE;
1030 UINT arc;
1031
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001032 arc = ACTION_CustomAction(package, action, script, force);
Aric Stewart3f318602005-02-01 18:46:26 +00001033
1034 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1035 {
1036 *rc = arc;
1037 ret = TRUE;
1038 }
1039 return ret;
1040}
Aric Stewart401bd3f2004-06-28 20:34:35 +00001041
1042/*
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001043 * A lot of actions are really important even if they don't do anything
1044 * explicit... Lots of properties are set at the beginning of the installation
1045 * CostFinalize does a bunch of work to translate the directories and such
Aric Stewart401bd3f2004-06-28 20:34:35 +00001046 *
Mike McCormack6e2bca32004-07-04 00:25:00 +00001047 * But until I get write access to the database that is hard, so I am going to
Aric Stewart401bd3f2004-06-28 20:34:35 +00001048 * hack it to see if I can get something to run.
1049 */
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001050UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
Aric Stewart401bd3f2004-06-28 20:34:35 +00001051{
Aric Stewartd2c395a2004-07-06 18:48:15 +00001052 UINT rc = ERROR_SUCCESS;
Aric Stewart3f318602005-02-01 18:46:26 +00001053 BOOL handled;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001054
1055 TRACE("Performing action (%s)\n",debugstr_w(action));
1056
Aric Stewart9cd707d2005-05-27 19:24:22 +00001057 handled = ACTION_HandleStandardAction(package, action, &rc, force);
Aric Stewart7d3e5972004-07-04 00:36:58 +00001058
Aric Stewart3f318602005-02-01 18:46:26 +00001059 if (!handled)
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001060 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
Aric Stewart3f318602005-02-01 18:46:26 +00001061
Aric Stewart90c57392005-01-31 16:23:12 +00001062 if (!handled)
1063 {
Mike McCormack54a28912005-09-06 09:23:18 +00001064 FIXME("unhandled msi action %s\n",debugstr_w(action));
Aric Stewart3f318602005-02-01 18:46:26 +00001065 rc = ERROR_FUNCTION_NOT_CALLED;
1066 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00001067
Aric Stewart3f318602005-02-01 18:46:26 +00001068 return rc;
1069}
1070
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001071UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
Aric Stewart3f318602005-02-01 18:46:26 +00001072{
1073 UINT rc = ERROR_SUCCESS;
1074 BOOL handled = FALSE;
1075
1076 TRACE("Performing action (%s)\n",debugstr_w(action));
1077
Aric Stewart9cd707d2005-05-27 19:24:22 +00001078 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
Aric Stewart3f318602005-02-01 18:46:26 +00001079
1080 if (!handled)
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001081 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
Aric Stewart3f318602005-02-01 18:46:26 +00001082
Mike McCormack4f634a32005-07-06 15:44:51 +00001083 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1084 handled = TRUE;
Mike McCormack34d4a022005-02-09 13:24:31 +00001085
Aric Stewart3f318602005-02-01 18:46:26 +00001086 if (!handled)
1087 {
Mike McCormack54a28912005-09-06 09:23:18 +00001088 FIXME("unhandled msi action %s\n",debugstr_w(action));
Aric Stewart3f318602005-02-01 18:46:26 +00001089 rc = ERROR_FUNCTION_NOT_CALLED;
Aric Stewart90c57392005-01-31 16:23:12 +00001090 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00001091
Aric Stewartd2c395a2004-07-06 18:48:15 +00001092 return rc;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001093}
1094
Aric Stewart2274ff12005-06-21 20:03:46 +00001095
1096/*
1097 * Actual Action Handlers
1098 */
1099
1100static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1101{
1102 MSIPACKAGE *package = (MSIPACKAGE*)param;
1103 LPCWSTR dir;
1104 LPWSTR full_path;
1105 MSIRECORD *uirow;
1106 MSIFOLDER *folder;
1107
1108 dir = MSI_RecordGetString(row,1);
1109 if (!dir)
1110 {
Francois Gouget0edbaf72005-11-10 12:14:56 +00001111 ERR("Unable to get folder id\n");
Aric Stewart2274ff12005-06-21 20:03:46 +00001112 return ERROR_SUCCESS;
1113 }
1114
James Hawkins8cedb212007-03-29 02:38:57 -05001115 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
Aric Stewart2274ff12005-06-21 20:03:46 +00001116 if (!full_path)
1117 {
1118 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1119 return ERROR_SUCCESS;
1120 }
1121
1122 TRACE("Folder is %s\n",debugstr_w(full_path));
1123
1124 /* UI stuff */
1125 uirow = MSI_CreateRecord(1);
1126 MSI_RecordSetStringW(uirow,1,full_path);
1127 ui_actiondata(package,szCreateFolders,uirow);
1128 msiobj_release( &uirow->hdr );
1129
1130 if (folder->State == 0)
1131 create_full_pathW(full_path);
1132
1133 folder->State = 3;
1134
Mike McCormackee034ba2005-09-20 11:59:14 +00001135 msi_free(full_path);
Aric Stewart2274ff12005-06-21 20:03:46 +00001136 return ERROR_SUCCESS;
1137}
1138
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001139/* FIXME: probably should merge this with the above function */
1140static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1141{
1142 UINT rc = ERROR_SUCCESS;
1143 MSIFOLDER *folder;
1144 LPWSTR install_path;
1145
James Hawkins8cedb212007-03-29 02:38:57 -05001146 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001147 if (!install_path)
1148 return ERROR_FUNCTION_FAILED;
1149
1150 /* create the path */
1151 if (folder->State == 0)
1152 {
1153 create_full_pathW(install_path);
1154 folder->State = 2;
1155 }
1156 msi_free(install_path);
1157
1158 return rc;
1159}
Aric Stewart2274ff12005-06-21 20:03:46 +00001160
Mike McCormack9c845852005-10-29 11:29:17 +00001161UINT msi_create_component_directories( MSIPACKAGE *package )
1162{
1163 MSICOMPONENT *comp;
1164
1165 /* create all the folders required by the components are going to install */
1166 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1167 {
Mike McCormackd693f462005-10-29 11:36:48 +00001168 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Mike McCormack9c845852005-10-29 11:29:17 +00001169 continue;
1170 msi_create_directory( package, comp->Directory );
1171 }
1172
1173 return ERROR_SUCCESS;
1174}
1175
Aric Stewart401bd3f2004-06-28 20:34:35 +00001176/*
1177 * Also we cannot enable/disable components either, so for now I am just going
Mike McCormack6e2bca32004-07-04 00:25:00 +00001178 * to do all the directories for all the components.
Aric Stewart401bd3f2004-06-28 20:34:35 +00001179 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001180static UINT ACTION_CreateFolders(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00001181{
Aric Stewart8e233e92005-03-01 11:45:19 +00001182 static const WCHAR ExecSeqQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001183 {'S','E','L','E','C','T',' ',
1184 '`','D','i','r','e','c','t','o','r','y','_','`',
Aric Stewart8e233e92005-03-01 11:45:19 +00001185 ' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001186 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00001187 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001188 MSIQUERY *view;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001189
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001190 /* create all the empty folders specified in the CreateFolder table */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001191 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
Aric Stewart401bd3f2004-06-28 20:34:35 +00001192 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00001193 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001194
Aric Stewart2274ff12005-06-21 20:03:46 +00001195 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001196 msiobj_release(&view->hdr);
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001197
Mike McCormack9c845852005-10-29 11:29:17 +00001198 msi_create_component_directories( package );
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001199
Aric Stewart401bd3f2004-06-28 20:34:35 +00001200 return rc;
1201}
1202
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001203static UINT load_component( MSIRECORD *row, LPVOID param )
Aric Stewartbdb29552004-07-04 00:32:48 +00001204{
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001205 MSIPACKAGE *package = param;
Mike McCormack38d67a42005-08-22 09:15:23 +00001206 MSICOMPONENT *comp;
Aric Stewartbdb29552004-07-04 00:32:48 +00001207
Mike McCormackee034ba2005-09-20 11:59:14 +00001208 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
Mike McCormack38d67a42005-08-22 09:15:23 +00001209 if (!comp)
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001210 return ERROR_FUNCTION_FAILED;
1211
1212 list_add_tail( &package->components, &comp->entry );
Mike McCormack38d67a42005-08-22 09:15:23 +00001213
Aric Stewartbdb29552004-07-04 00:32:48 +00001214 /* fill in the data */
Mike McCormack51c66182005-10-27 12:36:12 +00001215 comp->Component = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001216
Mike McCormackefcc1ec2005-09-12 12:07:15 +00001217 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
Aric Stewartbdb29552004-07-04 00:32:48 +00001218
Mike McCormack51c66182005-10-27 12:36:12 +00001219 comp->ComponentId = msi_dup_record_field( row, 2 );
1220 comp->Directory = msi_dup_record_field( row, 3 );
Mike McCormack38d67a42005-08-22 09:15:23 +00001221 comp->Attributes = MSI_RecordGetInteger(row,4);
Mike McCormack51c66182005-10-27 12:36:12 +00001222 comp->Condition = msi_dup_record_field( row, 5 );
1223 comp->KeyPath = msi_dup_record_field( row, 6 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001224
James Hawkinsd893cb72006-09-20 19:55:01 -07001225 comp->Installed = INSTALLSTATE_UNKNOWN;
Mike McCormack575cc672006-10-26 14:09:29 +09001226 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
Aric Stewartfbdd7092004-12-27 19:06:22 +00001227
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001228 return ERROR_SUCCESS;
1229}
Aric Stewartbdb29552004-07-04 00:32:48 +00001230
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001231static UINT load_all_components( MSIPACKAGE *package )
1232{
1233 static const WCHAR query[] = {
1234 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1235 '`','C','o','m','p','o','n','e','n','t','`',0 };
1236 MSIQUERY *view;
1237 UINT r;
1238
1239 if (!list_empty(&package->components))
1240 return ERROR_SUCCESS;
1241
1242 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1243 if (r != ERROR_SUCCESS)
1244 return r;
1245
1246 r = MSI_IterateRecords(view, NULL, load_component, package);
1247 msiobj_release(&view->hdr);
1248 return r;
Aric Stewartbdb29552004-07-04 00:32:48 +00001249}
1250
Aric Stewart04598242005-06-23 16:43:24 +00001251typedef struct {
1252 MSIPACKAGE *package;
Mike McCormack1da28582005-08-22 14:09:17 +00001253 MSIFEATURE *feature;
Aric Stewart04598242005-06-23 16:43:24 +00001254} _ilfs;
1255
Mike McCormack38d67a42005-08-22 09:15:23 +00001256static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001257{
1258 ComponentList *cl;
1259
Mike McCormackee034ba2005-09-20 11:59:14 +00001260 cl = msi_alloc( sizeof (*cl) );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001261 if ( !cl )
1262 return ERROR_NOT_ENOUGH_MEMORY;
Mike McCormack38d67a42005-08-22 09:15:23 +00001263 cl->component = comp;
Mike McCormack1da28582005-08-22 14:09:17 +00001264 list_add_tail( &feature->Components, &cl->entry );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001265
1266 return ERROR_SUCCESS;
1267}
1268
James Hawkins545d0e72006-09-20 19:59:19 -07001269static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1270{
1271 FeatureList *fl;
1272
1273 fl = msi_alloc( sizeof(*fl) );
1274 if ( !fl )
1275 return ERROR_NOT_ENOUGH_MEMORY;
1276 fl->feature = child;
1277 list_add_tail( &parent->Children, &fl->entry );
1278
1279 return ERROR_SUCCESS;
1280}
1281
Aric Stewart04598242005-06-23 16:43:24 +00001282static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1283{
1284 _ilfs* ilfs= (_ilfs*)param;
1285 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00001286 MSICOMPONENT *comp;
Aric Stewart04598242005-06-23 16:43:24 +00001287
1288 component = MSI_RecordGetString(row,1);
1289
1290 /* check to see if the component is already loaded */
Mike McCormack38d67a42005-08-22 09:15:23 +00001291 comp = get_loaded_component( ilfs->package, component );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001292 if (!comp)
Aric Stewart04598242005-06-23 16:43:24 +00001293 {
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001294 ERR("unknown component %s\n", debugstr_w(component));
1295 return ERROR_FUNCTION_FAILED;
Aric Stewart04598242005-06-23 16:43:24 +00001296 }
1297
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001298 add_feature_component( ilfs->feature, comp );
1299 comp->Enabled = TRUE;
Aric Stewart04598242005-06-23 16:43:24 +00001300
1301 return ERROR_SUCCESS;
1302}
1303
James Hawkins545d0e72006-09-20 19:59:19 -07001304static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1305{
1306 MSIFEATURE *feature;
1307
1308 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1309 {
1310 if ( !lstrcmpW( feature->Feature, name ) )
1311 return feature;
1312 }
1313
1314 return NULL;
1315}
1316
Aric Stewart04598242005-06-23 16:43:24 +00001317static UINT load_feature(MSIRECORD * row, LPVOID param)
1318{
1319 MSIPACKAGE* package = (MSIPACKAGE*)param;
Mike McCormack1da28582005-08-22 14:09:17 +00001320 MSIFEATURE* feature;
Aric Stewart8e233e92005-03-01 11:45:19 +00001321 static const WCHAR Query1[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001322 {'S','E','L','E','C','T',' ',
1323 '`','C','o','m','p','o','n','e','n','t','_','`',
1324 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1325 'C','o','m','p','o','n','e','n','t','s','`',' ',
1326 'W','H','E','R','E',' ',
1327 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001328 MSIQUERY * view;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001329 UINT rc;
Aric Stewart04598242005-06-23 16:43:24 +00001330 _ilfs ilfs;
1331
Aric Stewartbdb29552004-07-04 00:32:48 +00001332 /* fill in the data */
1333
Mike McCormackee034ba2005-09-20 11:59:14 +00001334 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
Mike McCormack1da28582005-08-22 14:09:17 +00001335 if (!feature)
1336 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartbdb29552004-07-04 00:32:48 +00001337
James Hawkins545d0e72006-09-20 19:59:19 -07001338 list_init( &feature->Children );
Mike McCormack1da28582005-08-22 14:09:17 +00001339 list_init( &feature->Components );
Aric Stewartbdb29552004-07-04 00:32:48 +00001340
Mike McCormack51c66182005-10-27 12:36:12 +00001341 feature->Feature = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001342
Mike McCormack1da28582005-08-22 14:09:17 +00001343 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
Aric Stewartbdb29552004-07-04 00:32:48 +00001344
Mike McCormack51c66182005-10-27 12:36:12 +00001345 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1346 feature->Title = msi_dup_record_field( row, 3 );
1347 feature->Description = msi_dup_record_field( row, 4 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001348
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001349 if (!MSI_RecordIsNull(row,5))
Mike McCormack1da28582005-08-22 14:09:17 +00001350 feature->Display = MSI_RecordGetInteger(row,5);
Aric Stewartbdb29552004-07-04 00:32:48 +00001351
Mike McCormack1da28582005-08-22 14:09:17 +00001352 feature->Level= MSI_RecordGetInteger(row,6);
Mike McCormack51c66182005-10-27 12:36:12 +00001353 feature->Directory = msi_dup_record_field( row, 7 );
Mike McCormack1da28582005-08-22 14:09:17 +00001354 feature->Attributes = MSI_RecordGetInteger(row,8);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001355
James Hawkinsca5c1102006-09-20 19:53:56 -07001356 feature->Installed = INSTALLSTATE_UNKNOWN;
Mike McCormack575cc672006-10-26 14:09:29 +09001357 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
Mike McCormack1da28582005-08-22 14:09:17 +00001358
1359 list_add_tail( &package->features, &feature->entry );
Aric Stewartbdb29552004-07-04 00:32:48 +00001360
1361 /* load feature components */
1362
Mike McCormack1da28582005-08-22 14:09:17 +00001363 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001364 if (rc != ERROR_SUCCESS)
Aric Stewart04598242005-06-23 16:43:24 +00001365 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001366
Mike McCormack1da28582005-08-22 14:09:17 +00001367 ilfs.package = package;
1368 ilfs.feature = feature;
1369
Aric Stewart04598242005-06-23 16:43:24 +00001370 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001371 msiobj_release(&view->hdr);
Aric Stewart04598242005-06-23 16:43:24 +00001372
1373 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001374}
1375
James Hawkins545d0e72006-09-20 19:59:19 -07001376static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1377{
1378 MSIPACKAGE* package = (MSIPACKAGE*)param;
1379 MSIFEATURE *parent, *child;
1380
1381 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1382 if (!child)
1383 return ERROR_FUNCTION_FAILED;
1384
1385 if (!child->Feature_Parent)
1386 return ERROR_SUCCESS;
1387
1388 parent = find_feature_by_name( package, child->Feature_Parent );
1389 if (!parent)
1390 return ERROR_FUNCTION_FAILED;
1391
1392 add_feature_child( parent, child );
1393 return ERROR_SUCCESS;
1394}
1395
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001396static UINT load_all_features( MSIPACKAGE *package )
1397{
1398 static const WCHAR query[] = {
1399 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1400 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1401 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1402 MSIQUERY *view;
1403 UINT r;
1404
1405 if (!list_empty(&package->features))
1406 return ERROR_SUCCESS;
1407
1408 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1409 if (r != ERROR_SUCCESS)
1410 return r;
1411
1412 r = MSI_IterateRecords( view, NULL, load_feature, package );
James Hawkins545d0e72006-09-20 19:59:19 -07001413 if (r != ERROR_SUCCESS)
1414 return r;
1415
1416 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001417 msiobj_release( &view->hdr );
James Hawkins545d0e72006-09-20 19:59:19 -07001418
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001419 return r;
1420}
1421
Mike McCormackc1513be2006-03-21 19:40:36 +09001422static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1423{
1424 if (!p)
1425 return p;
1426 p = strchrW(p, ch);
1427 if (!p)
1428 return p;
1429 *p = 0;
1430 return p+1;
1431}
1432
James Hawkins41607222007-11-25 18:01:19 -06001433static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1434{
1435 static const WCHAR query[] = {
1436 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1437 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1438 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1439 MSIQUERY *view = NULL;
James Hawkins1277e1b2007-12-14 15:18:05 -06001440 MSIRECORD *row = NULL;
James Hawkins41607222007-11-25 18:01:19 -06001441 UINT r;
1442
1443 TRACE("%s\n", debugstr_w(file->File));
1444
1445 r = MSI_OpenQuery(package->db, &view, query, file->File);
1446 if (r != ERROR_SUCCESS)
1447 goto done;
1448
1449 r = MSI_ViewExecute(view, NULL);
1450 if (r != ERROR_SUCCESS)
1451 goto done;
1452
1453 r = MSI_ViewFetch(view, &row);
1454 if (r != ERROR_SUCCESS)
1455 goto done;
1456
1457 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1458 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1459 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1460 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1461 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1462
1463done:
1464 if (view) msiobj_release(&view->hdr);
James Hawkins1277e1b2007-12-14 15:18:05 -06001465 if (row) msiobj_release(&row->hdr);
James Hawkins41607222007-11-25 18:01:19 -06001466 return r;
1467}
1468
Aric Stewart04598242005-06-23 16:43:24 +00001469static UINT load_file(MSIRECORD *row, LPVOID param)
Aric Stewartc5a14432005-05-18 17:46:12 +00001470{
Aric Stewart04598242005-06-23 16:43:24 +00001471 MSIPACKAGE* package = (MSIPACKAGE*)param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00001472 LPCWSTR component;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001473 MSIFILE *file;
Aric Stewartc5a14432005-05-18 17:46:12 +00001474
1475 /* fill in the data */
1476
Mike McCormackee034ba2005-09-20 11:59:14 +00001477 file = msi_alloc_zero( sizeof (MSIFILE) );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001478 if (!file)
1479 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartc5a14432005-05-18 17:46:12 +00001480
Mike McCormack51c66182005-10-27 12:36:12 +00001481 file->File = msi_dup_record_field( row, 1 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001482
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001483 component = MSI_RecordGetString( row, 2 );
1484 file->Component = get_loaded_component( package, component );
Aric Stewart09b0aba2005-06-09 20:30:59 +00001485
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001486 if (!file->Component)
Aric Stewart09b0aba2005-06-09 20:30:59 +00001487 ERR("Unfound Component %s\n",debugstr_w(component));
Aric Stewartc5a14432005-05-18 17:46:12 +00001488
Mike McCormack51c66182005-10-27 12:36:12 +00001489 file->FileName = msi_dup_record_field( row, 3 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001490 reduce_to_longfilename( file->FileName );
Aric Stewartc5a14432005-05-18 17:46:12 +00001491
Mike McCormack51c66182005-10-27 12:36:12 +00001492 file->ShortName = msi_dup_record_field( row, 3 );
Mike McCormackc1513be2006-03-21 19:40:36 +09001493 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
Aric Stewartc5a14432005-05-18 17:46:12 +00001494
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001495 file->FileSize = MSI_RecordGetInteger( row, 4 );
Mike McCormack51c66182005-10-27 12:36:12 +00001496 file->Version = msi_dup_record_field( row, 5 );
1497 file->Language = msi_dup_record_field( row, 6 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001498 file->Attributes = MSI_RecordGetInteger( row, 7 );
1499 file->Sequence = MSI_RecordGetInteger( row, 8 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001500
Mike McCormackdded8fb2005-11-02 10:56:42 +00001501 file->state = msifs_invalid;
Aric Stewartc5a14432005-05-18 17:46:12 +00001502
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001503 /* if the compressed bits are not set in the file attributes,
1504 * then read the information from the package word count property
1505 */
James Hawkins98d14862006-07-31 11:15:52 -07001506 if (file->Attributes & msidbFileAttributesCompressed)
1507 {
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001508 file->IsCompressed = TRUE;
1509 }
1510 else if (file->Attributes & msidbFileAttributesNoncompressed)
1511 {
1512 file->IsCompressed = FALSE;
1513 }
1514 else
1515 {
1516 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1517 }
1518
James Hawkins41607222007-11-25 18:01:19 -06001519 load_file_hash(package, file);
1520
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001521 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1522
1523 list_add_tail( &package->files, &file->entry );
Aric Stewartc5a14432005-05-18 17:46:12 +00001524
1525 return ERROR_SUCCESS;
1526}
1527
1528static UINT load_all_files(MSIPACKAGE *package)
1529{
1530 MSIQUERY * view;
Aric Stewartc5a14432005-05-18 17:46:12 +00001531 UINT rc;
1532 static const WCHAR Query[] =
1533 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001534 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1535 '`','S','e','q','u','e','n','c','e','`', 0};
Aric Stewartc5a14432005-05-18 17:46:12 +00001536
Mike McCormack9a9195d2006-07-19 17:01:07 +09001537 if (!list_empty(&package->files))
1538 return ERROR_SUCCESS;
1539
Aric Stewartc5a14432005-05-18 17:46:12 +00001540 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1541 if (rc != ERROR_SUCCESS)
1542 return ERROR_SUCCESS;
Aric Stewartc5a14432005-05-18 17:46:12 +00001543
Aric Stewart04598242005-06-23 16:43:24 +00001544 rc = MSI_IterateRecords(view, NULL, load_file, package);
Aric Stewartc5a14432005-05-18 17:46:12 +00001545 msiobj_release(&view->hdr);
1546
1547 return ERROR_SUCCESS;
1548}
1549
Mike McCormack7eb27022006-11-22 15:13:12 +09001550static UINT load_folder( MSIRECORD *row, LPVOID param )
1551{
1552 MSIPACKAGE *package = param;
1553 static const WCHAR szDot[] = { '.',0 };
1554 static WCHAR szEmpty[] = { 0 };
1555 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1556 MSIFOLDER *folder;
1557
1558 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1559 if (!folder)
1560 return ERROR_NOT_ENOUGH_MEMORY;
1561
1562 folder->Directory = msi_dup_record_field( row, 1 );
1563
1564 TRACE("%s\n", debugstr_w(folder->Directory));
1565
1566 p = msi_dup_record_field(row, 3);
1567
1568 /* split src and target dir */
1569 tgt_short = p;
1570 src_short = folder_split_path( p, ':' );
1571
1572 /* split the long and short paths */
1573 tgt_long = folder_split_path( tgt_short, '|' );
1574 src_long = folder_split_path( src_short, '|' );
1575
1576 /* check for no-op dirs */
1577 if (!lstrcmpW(szDot, tgt_short))
1578 tgt_short = szEmpty;
1579 if (!lstrcmpW(szDot, src_short))
1580 src_short = szEmpty;
1581
1582 if (!tgt_long)
1583 tgt_long = tgt_short;
1584
1585 if (!src_short) {
1586 src_short = tgt_short;
1587 src_long = tgt_long;
1588 }
1589
1590 if (!src_long)
1591 src_long = src_short;
1592
1593 /* FIXME: use the target short path too */
1594 folder->TargetDefault = strdupW(tgt_long);
1595 folder->SourceShortPath = strdupW(src_short);
1596 folder->SourceLongPath = strdupW(src_long);
1597 msi_free(p);
1598
1599 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1600 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1601 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1602
1603 folder->Parent = msi_dup_record_field( row, 2 );
1604
1605 folder->Property = msi_dup_property( package, folder->Directory );
1606
1607 list_add_tail( &package->folders, &folder->entry );
1608
1609 TRACE("returning %p\n", folder);
1610
1611 return ERROR_SUCCESS;
1612}
1613
1614static UINT load_all_folders( MSIPACKAGE *package )
1615{
1616 static const WCHAR query[] = {
1617 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1618 '`','D','i','r','e','c','t','o','r','y','`',0 };
1619 MSIQUERY *view;
1620 UINT r;
1621
1622 if (!list_empty(&package->folders))
1623 return ERROR_SUCCESS;
1624
1625 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1626 if (r != ERROR_SUCCESS)
1627 return r;
1628
1629 r = MSI_IterateRecords(view, NULL, load_folder, package);
1630 msiobj_release(&view->hdr);
1631 return r;
1632}
Aric Stewartc5a14432005-05-18 17:46:12 +00001633
Aric Stewartbdb29552004-07-04 00:32:48 +00001634/*
Mike McCormack9a9195d2006-07-19 17:01:07 +09001635 * I am not doing any of the costing functionality yet.
Aric Stewartbdb29552004-07-04 00:32:48 +00001636 * Mostly looking at doing the Component and Feature loading
1637 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001638 * The native MSI does A LOT of modification to tables here. Mostly adding
Mike McCormack9a9195d2006-07-19 17:01:07 +09001639 * a lot of temporary columns to the Feature and Component tables.
Aric Stewartbdb29552004-07-04 00:32:48 +00001640 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001641 * note: Native msi also tracks the short filename. But I am only going to
Aric Stewartbdb29552004-07-04 00:32:48 +00001642 * track the long ones. Also looking at this directory table
1643 * it appears that the directory table does not get the parents
Mike McCormack9a9195d2006-07-19 17:01:07 +09001644 * resolved base on property only based on their entries in the
Aric Stewartbdb29552004-07-04 00:32:48 +00001645 * directory table.
1646 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001647static UINT ACTION_CostInitialize(MSIPACKAGE *package)
Aric Stewartbdb29552004-07-04 00:32:48 +00001648{
Aric Stewart8e233e92005-03-01 11:45:19 +00001649 static const WCHAR szCosting[] =
1650 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001651 static const WCHAR szZero[] = { '0', 0 };
Aric Stewartbdb29552004-07-04 00:32:48 +00001652
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001653 MSI_SetPropertyW(package, szCosting, szZero);
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001654 MSI_SetPropertyW(package, cszRootDrive, c_colon);
Aric Stewartbdb29552004-07-04 00:32:48 +00001655
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001656 load_all_components( package );
1657 load_all_features( package );
1658 load_all_files( package );
Mike McCormack7eb27022006-11-22 15:13:12 +09001659 load_all_folders( package );
Aric Stewartec688fb2004-07-04 00:35:52 +00001660
Aric Stewartec688fb2004-07-04 00:35:52 +00001661 return ERROR_SUCCESS;
1662}
1663
Mike McCormackf9acfe62005-06-07 20:29:51 +00001664static UINT execute_script(MSIPACKAGE *package, UINT script )
Aric Stewart9cd707d2005-05-27 19:24:22 +00001665{
James Hawkinsbb54ed12007-11-05 04:36:49 -05001666 UINT i;
Aric Stewart9cd707d2005-05-27 19:24:22 +00001667 UINT rc = ERROR_SUCCESS;
1668
1669 TRACE("Executing Script %i\n",script);
1670
Mike McCormackaa81e4f2006-01-10 12:09:19 +01001671 if (!package->script)
1672 {
1673 ERR("no script!\n");
1674 return ERROR_FUNCTION_FAILED;
1675 }
1676
Aric Stewart9cd707d2005-05-27 19:24:22 +00001677 for (i = 0; i < package->script->ActionCount[script]; i++)
1678 {
1679 LPWSTR action;
1680 action = package->script->Actions[script][i];
1681 ui_actionstart(package, action);
1682 TRACE("Executing Action (%s)\n",debugstr_w(action));
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001683 rc = ACTION_PerformAction(package, action, script, TRUE);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001684 if (rc != ERROR_SUCCESS)
1685 break;
1686 }
Mike McCormackf86cfd42006-11-02 18:12:43 +09001687 msi_free_action_script(package, script);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001688 return rc;
1689}
1690
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001691static UINT ACTION_FileCost(MSIPACKAGE *package)
Aric Stewartec688fb2004-07-04 00:35:52 +00001692{
Aric Stewartbdb29552004-07-04 00:32:48 +00001693 return ERROR_SUCCESS;
1694}
1695
Mike McCormackb7669152006-10-30 16:35:09 +09001696static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001697{
Mike McCormack38d67a42005-08-22 09:15:23 +00001698 MSICOMPONENT *comp;
Aric Stewart78a04e32005-02-22 15:47:00 +00001699
Mike McCormack38d67a42005-08-22 09:15:23 +00001700 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001701 {
1702 INSTALLSTATE res;
James Hawkins32f57022006-09-20 19:57:03 -07001703
1704 if (!comp->ComponentId)
1705 continue;
1706
Mike McCormackb7669152006-10-30 16:35:09 +09001707 res = MsiGetComponentPathW( package->ProductCode,
Mike McCormack38d67a42005-08-22 09:15:23 +00001708 comp->ComponentId, NULL, NULL);
Aric Stewart78a04e32005-02-22 15:47:00 +00001709 if (res < 0)
1710 res = INSTALLSTATE_ABSENT;
Mike McCormack38d67a42005-08-22 09:15:23 +00001711 comp->Installed = res;
Aric Stewart78a04e32005-02-22 15:47:00 +00001712 }
Mike McCormackb7669152006-10-30 16:35:09 +09001713}
1714
1715/* scan for and update current install states */
1716static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1717{
1718 MSICOMPONENT *comp;
1719 MSIFEATURE *feature;
Aric Stewart78a04e32005-02-22 15:47:00 +00001720
Mike McCormack1da28582005-08-22 14:09:17 +00001721 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001722 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001723 ComponentList *cl;
James Hawkins545d0e72006-09-20 19:59:19 -07001724 INSTALLSTATE res = INSTALLSTATE_ABSENT;
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001725
Mike McCormack1da28582005-08-22 14:09:17 +00001726 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001727 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001728 comp= cl->component;
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001729
James Hawkins32f57022006-09-20 19:57:03 -07001730 if (!comp->ComponentId)
1731 {
1732 res = INSTALLSTATE_ABSENT;
1733 break;
1734 }
1735
James Hawkins545d0e72006-09-20 19:59:19 -07001736 if (res == INSTALLSTATE_ABSENT)
Mike McCormack38d67a42005-08-22 09:15:23 +00001737 res = comp->Installed;
Aric Stewart78a04e32005-02-22 15:47:00 +00001738 else
1739 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001740 if (res == comp->Installed)
Aric Stewart78a04e32005-02-22 15:47:00 +00001741 continue;
1742
Paul Vriensded99432006-11-12 12:01:26 +01001743 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
James Hawkins32f57022006-09-20 19:57:03 -07001744 res != INSTALLSTATE_SOURCE)
1745 {
1746 res = INSTALLSTATE_INCOMPLETE;
1747 }
Aric Stewart78a04e32005-02-22 15:47:00 +00001748 }
1749 }
Mike McCormack8aa1a912005-08-25 19:19:10 +00001750 feature->Installed = res;
Aric Stewart78a04e32005-02-22 15:47:00 +00001751 }
1752}
1753
Aric Stewart78a04e32005-02-22 15:47:00 +00001754static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1755 INSTALLSTATE state)
Aric Stewartae1aa322004-12-27 19:02:59 +00001756{
Aric Stewartae1aa322004-12-27 19:02:59 +00001757 static const WCHAR all[]={'A','L','L',0};
Mike McCormack72faac02005-09-08 11:03:35 +00001758 LPWSTR override;
Mike McCormack1da28582005-08-22 14:09:17 +00001759 MSIFEATURE *feature;
Aric Stewartae1aa322004-12-27 19:02:59 +00001760
Mike McCormack062ad502005-09-15 15:04:08 +00001761 override = msi_dup_property( package, property );
Mike McCormack72faac02005-09-08 11:03:35 +00001762 if (!override)
1763 return FALSE;
Mike McCormack575cc672006-10-26 14:09:29 +09001764
Mike McCormack72faac02005-09-08 11:03:35 +00001765 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001766 {
Mike McCormack72faac02005-09-08 11:03:35 +00001767 if (strcmpiW(override,all)==0)
Mike McCormack575cc672006-10-26 14:09:29 +09001768 msi_feature_set_state( feature, state );
Mike McCormack72faac02005-09-08 11:03:35 +00001769 else
1770 {
1771 LPWSTR ptr = override;
1772 LPWSTR ptr2 = strchrW(override,',');
Aric Stewartd900b532004-12-27 19:12:35 +00001773
Mike McCormack72faac02005-09-08 11:03:35 +00001774 while (ptr)
1775 {
1776 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1777 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
Aric Stewartd900b532004-12-27 19:12:35 +00001778 {
Mike McCormack575cc672006-10-26 14:09:29 +09001779 msi_feature_set_state( feature, state );
Mike McCormack72faac02005-09-08 11:03:35 +00001780 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001781 }
Mike McCormack72faac02005-09-08 11:03:35 +00001782 if (ptr2)
1783 {
1784 ptr=ptr2+1;
1785 ptr2 = strchrW(ptr,',');
1786 }
1787 else
1788 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001789 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001790 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001791 }
Mike McCormackee034ba2005-09-20 11:59:14 +00001792 msi_free(override);
Aric Stewart78a04e32005-02-22 15:47:00 +00001793
Mike McCormack72faac02005-09-08 11:03:35 +00001794 return TRUE;
Aric Stewart78a04e32005-02-22 15:47:00 +00001795}
1796
James Hawkins7bcac312006-07-19 11:17:16 -07001797UINT MSI_SetFeatureStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001798{
Mike McCormack74f0de92005-09-29 10:32:39 +00001799 int install_level;
Aric Stewart8e233e92005-03-01 11:45:19 +00001800 static const WCHAR szlevel[] =
1801 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1802 static const WCHAR szAddLocal[] =
1803 {'A','D','D','L','O','C','A','L',0};
James Hawkinsc31fd432007-11-06 05:22:11 -06001804 static const WCHAR szAddSource[] =
1805 {'A','D','D','S','O','U','R','C','E',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00001806 static const WCHAR szRemove[] =
1807 {'R','E','M','O','V','E',0};
Aric Stewartd5655f92005-11-02 14:21:17 +00001808 static const WCHAR szReinstall[] =
1809 {'R','E','I','N','S','T','A','L','L',0};
Aric Stewart78a04e32005-02-22 15:47:00 +00001810 BOOL override = FALSE;
Mike McCormack38d67a42005-08-22 09:15:23 +00001811 MSICOMPONENT* component;
Mike McCormack1da28582005-08-22 14:09:17 +00001812 MSIFEATURE *feature;
1813
Aric Stewart78a04e32005-02-22 15:47:00 +00001814
1815 /* I do not know if this is where it should happen.. but */
1816
1817 TRACE("Checking Install Level\n");
1818
Mike McCormack74f0de92005-09-29 10:32:39 +00001819 install_level = msi_get_property_int( package, szlevel, 1 );
Aric Stewart78a04e32005-02-22 15:47:00 +00001820
Francois Gouget58162f82006-10-13 02:19:42 +02001821 /* ok here is the _real_ rub
Francois Gougetfbb33432005-03-02 13:53:50 +00001822 * all these activation/deactivation things happen in order and things
1823 * later on the list override things earlier on the list.
Aric Stewart78a04e32005-02-22 15:47:00 +00001824 * 1) INSTALLLEVEL processing
1825 * 2) ADDLOCAL
1826 * 3) REMOVE
1827 * 4) ADDSOURCE
1828 * 5) ADDDEFAULT
1829 * 6) REINSTALL
1830 * 7) COMPADDLOCAL
1831 * 8) COMPADDSOURCE
1832 * 9) FILEADDLOCAL
1833 * 10) FILEADDSOURCE
1834 * 11) FILEADDDEFAULT
Francois Gougetfbb33432005-03-02 13:53:50 +00001835 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1836 * ignored for all the features. seems strange, especially since it is not
Mike McCormack6395ff62006-10-26 12:34:52 +09001837 * documented anywhere, but it is how it works.
Aric Stewart78a04e32005-02-22 15:47:00 +00001838 *
Francois Gougetfbb33432005-03-02 13:53:50 +00001839 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1840 * REMOVE are the big ones, since we don't handle administrative installs
1841 * yet anyway.
Aric Stewart78a04e32005-02-22 15:47:00 +00001842 */
1843 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1844 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
James Hawkinsc31fd432007-11-06 05:22:11 -06001845 override |= process_state_property(package,szAddSource,INSTALLSTATE_SOURCE);
Aric Stewartd5655f92005-11-02 14:21:17 +00001846 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
Aric Stewart78a04e32005-02-22 15:47:00 +00001847
1848 if (!override)
Aric Stewartfbdd7092004-12-27 19:06:22 +00001849 {
Mike McCormack1da28582005-08-22 14:09:17 +00001850 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001851 {
Mike McCormack1da28582005-08-22 14:09:17 +00001852 BOOL feature_state = ((feature->Level > 0) &&
1853 (feature->Level <= install_level));
Aric Stewartae1aa322004-12-27 19:02:59 +00001854
Mike McCormack1da28582005-08-22 14:09:17 +00001855 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001856 {
Mike McCormack1da28582005-08-22 14:09:17 +00001857 if (feature->Attributes & msidbFeatureAttributesFavorSource)
Mike McCormack6395ff62006-10-26 12:34:52 +09001858 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
Mike McCormack1da28582005-08-22 14:09:17 +00001859 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
Mike McCormack6395ff62006-10-26 12:34:52 +09001860 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
Aric Stewartb39d8fc2005-05-13 13:56:39 +00001861 else
Mike McCormack6395ff62006-10-26 12:34:52 +09001862 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
Aric Stewartfbdd7092004-12-27 19:06:22 +00001863 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001864 }
James Hawkins545d0e72006-09-20 19:59:19 -07001865
1866 /* disable child features of unselected parent features */
1867 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1868 {
1869 FeatureList *fl;
1870
1871 if (feature->Level > 0 && feature->Level <= install_level)
1872 continue;
1873
1874 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
Mike McCormack6395ff62006-10-26 12:34:52 +09001875 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
James Hawkins545d0e72006-09-20 19:59:19 -07001876 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001877 }
Aric Stewart6999a042005-06-08 19:20:02 +00001878 else
1879 {
1880 /* set the Preselected Property */
1881 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1882 static const WCHAR szOne[] = { '1', 0 };
1883
1884 MSI_SetPropertyW(package,szPreselected,szOne);
1885 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001886
Aric Stewartfbdd7092004-12-27 19:06:22 +00001887 /*
Mike McCormack6395ff62006-10-26 12:34:52 +09001888 * now we want to enable or disable components base on feature
1889 */
Aric Stewartfbdd7092004-12-27 19:06:22 +00001890
Mike McCormack1da28582005-08-22 14:09:17 +00001891 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001892 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001893 ComponentList *cl;
1894
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001895 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
Mike McCormack97419ae2006-12-05 18:24:39 +09001896 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1897
1898 /* features with components that have compressed files are made local */
1899 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1900 {
1901 if (cl->component->Enabled &&
1902 cl->component->ForceLocalState &&
1903 feature->Action == INSTALLSTATE_SOURCE)
1904 {
1905 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1906 break;
1907 }
1908 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001909
Mike McCormack1da28582005-08-22 14:09:17 +00001910 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001911 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001912 component = cl->component;
Aric Stewartfbdd7092004-12-27 19:06:22 +00001913
Mike McCormack87fa8542006-11-10 15:38:51 +09001914 if (!component->Enabled)
1915 continue;
1916
Mike McCormack97419ae2006-12-05 18:24:39 +09001917 switch (feature->Action)
Mike McCormackad80ece2006-11-10 15:38:31 +09001918 {
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001919 case INSTALLSTATE_ABSENT:
1920 component->anyAbsent = 1;
1921 break;
Mike McCormack97419ae2006-12-05 18:24:39 +09001922 case INSTALLSTATE_ADVERTISED:
1923 component->hasAdvertiseFeature = 1;
1924 break;
1925 case INSTALLSTATE_SOURCE:
1926 component->hasSourceFeature = 1;
1927 break;
1928 case INSTALLSTATE_LOCAL:
1929 component->hasLocalFeature = 1;
1930 break;
1931 case INSTALLSTATE_DEFAULT:
1932 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1933 component->hasAdvertiseFeature = 1;
1934 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1935 component->hasSourceFeature = 1;
Mike McCormackad80ece2006-11-10 15:38:31 +09001936 else
Mike McCormack97419ae2006-12-05 18:24:39 +09001937 component->hasLocalFeature = 1;
1938 break;
1939 default:
1940 break;
James Hawkins929395c2006-10-19 15:51:33 -07001941 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001942 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001943 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001944
Mike McCormack38d67a42005-08-22 09:15:23 +00001945 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001946 {
Mike McCormack97419ae2006-12-05 18:24:39 +09001947 /* if the component isn't enabled, leave it alone */
1948 if (!component->Enabled)
1949 continue;
1950
1951 /* check if it's local or source */
1952 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1953 (component->hasLocalFeature || component->hasSourceFeature))
1954 {
1955 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1956 !component->ForceLocalState)
1957 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1958 else
1959 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1960 continue;
1961 }
1962
1963 /* if any feature is local, the component must be local too */
1964 if (component->hasLocalFeature)
1965 {
1966 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1967 continue;
1968 }
1969
1970 if (component->hasSourceFeature)
1971 {
1972 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1973 continue;
1974 }
1975
1976 if (component->hasAdvertiseFeature)
1977 {
1978 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1979 continue;
1980 }
1981
1982 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001983 if (component->anyAbsent)
1984 msi_component_set_state(component, INSTALLSTATE_ABSENT);
Mike McCormack97419ae2006-12-05 18:24:39 +09001985 }
1986
1987 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1988 {
Mike McCormack9efb7b72006-11-07 17:55:43 +09001989 if (component->Action == INSTALLSTATE_DEFAULT)
1990 {
1991 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1992 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1993 }
1994
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001995 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1996 debugstr_w(component->Component), component->Installed, component->Action);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001997 }
1998
1999
Aric Stewartae1aa322004-12-27 19:02:59 +00002000 return ERROR_SUCCESS;
2001}
2002
Aric Stewart443ad4d2005-06-21 20:50:12 +00002003static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
2004{
2005 MSIPACKAGE *package = (MSIPACKAGE*)param;
2006 LPCWSTR name;
2007 LPWSTR path;
James Hawkinsbaad8882007-05-01 03:19:50 -05002008 MSIFOLDER *f;
Aric Stewart443ad4d2005-06-21 20:50:12 +00002009
2010 name = MSI_RecordGetString(row,1);
2011
James Hawkinsbaad8882007-05-01 03:19:50 -05002012 f = get_loaded_folder(package, name);
2013 if (!f) return ERROR_SUCCESS;
2014
2015 /* reset the ResolvedTarget */
2016 msi_free(f->ResolvedTarget);
2017 f->ResolvedTarget = NULL;
2018
Aric Stewart443ad4d2005-06-21 20:50:12 +00002019 /* This helper function now does ALL the work */
2020 TRACE("Dir %s ...\n",debugstr_w(name));
James Hawkins8cedb212007-03-29 02:38:57 -05002021 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
Aric Stewart443ad4d2005-06-21 20:50:12 +00002022 TRACE("resolves to %s\n",debugstr_w(path));
Mike McCormackee034ba2005-09-20 11:59:14 +00002023 msi_free(path);
Aric Stewart443ad4d2005-06-21 20:50:12 +00002024
2025 return ERROR_SUCCESS;
2026}
2027
2028static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
2029{
2030 MSIPACKAGE *package = (MSIPACKAGE*)param;
Mike McCormack1da28582005-08-22 14:09:17 +00002031 LPCWSTR name;
2032 MSIFEATURE *feature;
Aric Stewart443ad4d2005-06-21 20:50:12 +00002033
Mike McCormack1da28582005-08-22 14:09:17 +00002034 name = MSI_RecordGetString( row, 1 );
Aric Stewart443ad4d2005-06-21 20:50:12 +00002035
Mike McCormack1da28582005-08-22 14:09:17 +00002036 feature = get_loaded_feature( package, name );
2037 if (!feature)
2038 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
Aric Stewart443ad4d2005-06-21 20:50:12 +00002039 else
2040 {
2041 LPCWSTR Condition;
2042 Condition = MSI_RecordGetString(row,3);
2043
Aric Stewart0713f092005-06-24 11:51:29 +00002044 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
Aric Stewart443ad4d2005-06-21 20:50:12 +00002045 {
2046 int level = MSI_RecordGetInteger(row,2);
Mike McCormack1da28582005-08-22 14:09:17 +00002047 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
2048 feature->Level = level;
Aric Stewart443ad4d2005-06-21 20:50:12 +00002049 }
2050 }
2051 return ERROR_SUCCESS;
2052}
2053
Andrew Talbot020bda72007-01-12 16:47:57 +00002054static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
Mike McCormackd1723de2006-10-24 17:37:26 +09002055{
2056 static const WCHAR name_fmt[] =
2057 {'%','u','.','%','u','.','%','u','.','%','u',0};
2058 static WCHAR name[] = {'\\',0};
2059 VS_FIXEDFILEINFO *lpVer;
2060 WCHAR filever[0x100];
2061 LPVOID version;
2062 DWORD versize;
2063 DWORD handle;
2064 UINT sz;
2065
2066 TRACE("%s\n", debugstr_w(filename));
2067
2068 versize = GetFileVersionInfoSizeW( filename, &handle );
2069 if (!versize)
2070 return NULL;
2071
2072 version = msi_alloc( versize );
2073 GetFileVersionInfoW( filename, 0, versize, version );
2074
Rob Shearman9c6fac62007-06-26 22:22:52 +01002075 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2076 {
2077 msi_free( version );
2078 return NULL;
2079 }
Mike McCormackd1723de2006-10-24 17:37:26 +09002080
2081 sprintfW( filever, name_fmt,
2082 HIWORD(lpVer->dwFileVersionMS),
2083 LOWORD(lpVer->dwFileVersionMS),
2084 HIWORD(lpVer->dwFileVersionLS),
2085 LOWORD(lpVer->dwFileVersionLS));
2086
Rob Shearman023383a2007-06-26 22:23:30 +01002087 msi_free( version );
2088
Mike McCormackd1723de2006-10-24 17:37:26 +09002089 return strdupW( filever );
2090}
2091
Mike McCormackc5c55212006-11-07 15:05:48 +09002092static UINT msi_check_file_install_states( MSIPACKAGE *package )
Aric Stewart401bd3f2004-06-28 20:34:35 +00002093{
Mike McCormackc5c55212006-11-07 15:05:48 +09002094 LPWSTR file_version;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002095 MSIFILE *file;
Aric Stewartec688fb2004-07-04 00:35:52 +00002096
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002097 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartec688fb2004-07-04 00:35:52 +00002098 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00002099 MSICOMPONENT* comp = file->Component;
2100 LPWSTR p;
Aric Stewartec688fb2004-07-04 00:35:52 +00002101
Mike McCormackf11c8b02005-09-09 14:48:51 +00002102 if (!comp)
2103 continue;
Aric Stewartec688fb2004-07-04 00:35:52 +00002104
James Hawkinsd893cb72006-09-20 19:55:01 -07002105 if (file->IsCompressed)
James Hawkinsd893cb72006-09-20 19:55:01 -07002106 comp->ForceLocalState = TRUE;
James Hawkinsd893cb72006-09-20 19:55:01 -07002107
Mike McCormackf11c8b02005-09-09 14:48:51 +00002108 /* calculate target */
James Hawkins8cedb212007-03-29 02:38:57 -05002109 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002110
Mike McCormackee034ba2005-09-20 11:59:14 +00002111 msi_free(file->TargetPath);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002112
2113 TRACE("file %s is named %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09002114 debugstr_w(file->File), debugstr_w(file->FileName));
Mike McCormackf11c8b02005-09-09 14:48:51 +00002115
2116 file->TargetPath = build_directory_name(2, p, file->FileName);
2117
Mike McCormackee034ba2005-09-20 11:59:14 +00002118 msi_free(p);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002119
2120 TRACE("file %s resolves to %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09002121 debugstr_w(file->File), debugstr_w(file->TargetPath));
Mike McCormackf11c8b02005-09-09 14:48:51 +00002122
Mike McCormackddf0b592006-10-31 14:32:48 +09002123 /* don't check files of components that aren't installed */
2124 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2125 comp->Installed == INSTALLSTATE_ABSENT)
2126 {
2127 file->state = msifs_missing; /* assume files are missing */
2128 continue;
2129 }
2130
Mike McCormackf11c8b02005-09-09 14:48:51 +00002131 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
Aric Stewartec688fb2004-07-04 00:35:52 +00002132 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002133 file->state = msifs_missing;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002134 comp->Cost += file->FileSize;
Mike McCormackddf0b592006-10-31 14:32:48 +09002135 comp->Installed = INSTALLSTATE_INCOMPLETE;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002136 continue;
2137 }
Mike McCormackba8200b2004-12-22 15:25:30 +00002138
Mike McCormackd1723de2006-10-24 17:37:26 +09002139 if (file->Version &&
2140 (file_version = msi_get_disk_file_version( file->TargetPath )))
Mike McCormackf11c8b02005-09-09 14:48:51 +00002141 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00002142 TRACE("new %s old %s\n", debugstr_w(file->Version),
Mike McCormackd1723de2006-10-24 17:37:26 +09002143 debugstr_w(file_version));
2144 /* FIXME: seems like a bad way to compare version numbers */
2145 if (lstrcmpiW(file_version, file->Version)<0)
Aric Stewartec688fb2004-07-04 00:35:52 +00002146 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002147 file->state = msifs_overwrite;
Aric Stewartec688fb2004-07-04 00:35:52 +00002148 comp->Cost += file->FileSize;
Mike McCormackddf0b592006-10-31 14:32:48 +09002149 comp->Installed = INSTALLSTATE_INCOMPLETE;
Aric Stewartec688fb2004-07-04 00:35:52 +00002150 }
2151 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002152 file->state = msifs_present;
Mike McCormackd1723de2006-10-24 17:37:26 +09002153 msi_free( file_version );
Mike McCormackf11c8b02005-09-09 14:48:51 +00002154 }
2155 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002156 file->state = msifs_present;
Aric Stewartec688fb2004-07-04 00:35:52 +00002157 }
2158
Mike McCormackc5c55212006-11-07 15:05:48 +09002159 return ERROR_SUCCESS;
2160}
2161
2162/*
2163 * A lot is done in this function aside from just the costing.
2164 * The costing needs to be implemented at some point but for now I am going
2165 * to focus on the directory building
2166 *
2167 */
2168static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2169{
2170 static const WCHAR ExecSeqQuery[] =
2171 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2172 '`','D','i','r','e','c','t','o','r','y','`',0};
2173 static const WCHAR ConditionQuery[] =
2174 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2175 '`','C','o','n','d','i','t','i','o','n','`',0};
2176 static const WCHAR szCosting[] =
2177 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2178 static const WCHAR szlevel[] =
2179 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2180 static const WCHAR szOne[] = { '1', 0 };
2181 MSICOMPONENT *comp;
2182 UINT rc;
2183 MSIQUERY * view;
2184 LPWSTR level;
2185
2186 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2187 return ERROR_SUCCESS;
2188
2189 TRACE("Building Directory properties\n");
2190
2191 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2192 if (rc == ERROR_SUCCESS)
2193 {
2194 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2195 package);
2196 msiobj_release(&view->hdr);
2197 }
2198
2199 /* read components states from the registry */
2200 ACTION_GetComponentInstallStates(package);
2201
2202 TRACE("File calculations\n");
2203 msi_check_file_install_states( package );
2204
Aric Stewart7d3e5972004-07-04 00:36:58 +00002205 TRACE("Evaluating Condition Table\n");
Aric Stewart2e9b5f72004-07-04 00:31:17 +00002206
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002207 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
Aric Stewart84837d92004-07-20 01:22:37 +00002208 if (rc == ERROR_SUCCESS)
2209 {
Aric Stewart443ad4d2005-06-21 20:50:12 +00002210 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2211 package);
Mike McCormackac6a4132005-01-04 20:36:12 +00002212 msiobj_release(&view->hdr);
Aric Stewart84837d92004-07-20 01:22:37 +00002213 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002214
2215 TRACE("Enabling or Disabling Components\n");
Mike McCormack38d67a42005-08-22 09:15:23 +00002216 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewart7d3e5972004-07-04 00:36:58 +00002217 {
Mike McCormack9375fd92006-10-27 17:29:02 +09002218 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002219 {
Mike McCormack9375fd92006-10-27 17:29:02 +09002220 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2221 comp->Enabled = FALSE;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002222 }
2223 }
2224
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002225 MSI_SetPropertyW(package,szCosting,szOne);
Aric Stewart8cc14a92004-12-27 18:56:30 +00002226 /* set default run level if not set */
Mike McCormack062ad502005-09-15 15:04:08 +00002227 level = msi_dup_property( package, szlevel );
Aric Stewart8cc14a92004-12-27 18:56:30 +00002228 if (!level)
2229 MSI_SetPropertyW(package,szlevel, szOne);
Mike McCormackee034ba2005-09-20 11:59:14 +00002230 msi_free(level);
Aric Stewartae1aa322004-12-27 19:02:59 +00002231
Mike McCormackb7669152006-10-30 16:35:09 +09002232 ACTION_UpdateFeatureInstallStates(package);
Aric Stewartae1aa322004-12-27 19:02:59 +00002233
James Hawkins7c7f0bb2006-07-19 11:15:37 -07002234 return MSI_SetFeatureStates(package);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002235}
2236
Francois Gougetda8b3dd2005-01-26 21:09:04 +00002237/* OK this value is "interpreted" and then formatted based on the
Aric Stewart6e160f12004-06-29 04:07:22 +00002238 first few characters */
Aric Stewart09b0aba2005-06-09 20:30:59 +00002239static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
Aric Stewart401bd3f2004-06-28 20:34:35 +00002240 DWORD *size)
2241{
2242 LPSTR data = NULL;
James Hawkins2f658cb2008-02-04 19:06:53 -06002243
Aric Stewart6e160f12004-06-29 04:07:22 +00002244 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
Aric Stewart401bd3f2004-06-28 20:34:35 +00002245 {
Aric Stewart6e160f12004-06-29 04:07:22 +00002246 if (value[1]=='x')
2247 {
2248 LPWSTR ptr;
2249 CHAR byte[5];
Aric Stewart6186b2b2005-05-16 21:37:35 +00002250 LPWSTR deformated = NULL;
Aric Stewart6e160f12004-06-29 04:07:22 +00002251 int count;
2252
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002253 deformat_string(package, &value[2], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002254
2255 /* binary value type */
Aric Stewart6186b2b2005-05-16 21:37:35 +00002256 ptr = deformated;
2257 *type = REG_BINARY;
2258 if (strlenW(ptr)%2)
2259 *size = (strlenW(ptr)/2)+1;
2260 else
2261 *size = strlenW(ptr)/2;
2262
Mike McCormackee034ba2005-09-20 11:59:14 +00002263 data = msi_alloc(*size);
Aric Stewart6186b2b2005-05-16 21:37:35 +00002264
Aric Stewart6e160f12004-06-29 04:07:22 +00002265 byte[0] = '0';
2266 byte[1] = 'x';
2267 byte[4] = 0;
2268 count = 0;
Aric Stewart6186b2b2005-05-16 21:37:35 +00002269 /* if uneven pad with a zero in front */
2270 if (strlenW(ptr)%2)
2271 {
2272 byte[2]= '0';
2273 byte[3]= *ptr;
2274 ptr++;
2275 data[count] = (BYTE)strtol(byte,NULL,0);
2276 count ++;
2277 TRACE("Uneven byte count\n");
2278 }
Aric Stewart6e160f12004-06-29 04:07:22 +00002279 while (*ptr)
2280 {
2281 byte[2]= *ptr;
2282 ptr++;
2283 byte[3]= *ptr;
2284 ptr++;
2285 data[count] = (BYTE)strtol(byte,NULL,0);
2286 count ++;
2287 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002288 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002289
Mike McCormackf1d46462006-10-05 13:41:22 +09002290 TRACE("Data %i bytes(%i)\n",*size,count);
Aric Stewart6e160f12004-06-29 04:07:22 +00002291 }
2292 else
2293 {
2294 LPWSTR deformated;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002295 LPWSTR p;
2296 DWORD d = 0;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002297 deformat_string(package, &value[1], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002298
2299 *type=REG_DWORD;
2300 *size = sizeof(DWORD);
Mike McCormackee034ba2005-09-20 11:59:14 +00002301 data = msi_alloc(*size);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002302 p = deformated;
2303 if (*p == '-')
2304 p++;
2305 while (*p)
2306 {
2307 if ( (*p < '0') || (*p > '9') )
2308 break;
2309 d *= 10;
2310 d += (*p - '0');
2311 p++;
2312 }
2313 if (deformated[0] == '-')
2314 d = -d;
2315 *(LPDWORD)data = d;
Mike McCormackf1d46462006-10-05 13:41:22 +09002316 TRACE("DWORD %i\n",*(LPDWORD)data);
Aric Stewart6e160f12004-06-29 04:07:22 +00002317
Mike McCormackee034ba2005-09-20 11:59:14 +00002318 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002319 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002320 }
2321 else
2322 {
Aric Stewart54c67dd2005-01-25 20:17:09 +00002323 static const WCHAR szMulti[] = {'[','~',']',0};
Aric Stewart09b0aba2005-06-09 20:30:59 +00002324 LPCWSTR ptr;
James Hawkins2f658cb2008-02-04 19:06:53 -06002325 LPWSTR newdata;
Aric Stewart6e160f12004-06-29 04:07:22 +00002326 *type=REG_SZ;
2327
Aric Stewart401bd3f2004-06-28 20:34:35 +00002328 if (value[0]=='#')
Aric Stewart6e160f12004-06-29 04:07:22 +00002329 {
2330 if (value[1]=='%')
2331 {
2332 ptr = &value[2];
2333 *type=REG_EXPAND_SZ;
2334 }
2335 else
2336 ptr = &value[1];
2337 }
2338 else
Aric Stewart401bd3f2004-06-28 20:34:35 +00002339 ptr=value;
2340
Aric Stewart54c67dd2005-01-25 20:17:09 +00002341 if (strstrW(value,szMulti))
2342 *type = REG_MULTI_SZ;
2343
James Hawkins2f658cb2008-02-04 19:06:53 -06002344 /* remove initial delimiter */
2345 if (!strncmpW(value, szMulti, 3))
2346 ptr = value + 3;
2347
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002348 *size = deformat_string(package, ptr,(LPWSTR*)&data);
James Hawkins2f658cb2008-02-04 19:06:53 -06002349
2350 /* add double NULL terminator */
2351 if (*type == REG_MULTI_SZ)
2352 {
2353 *size += sizeof(WCHAR);
2354 newdata = msi_alloc(*size);
2355 if (!newdata)
2356 {
2357 msi_free(data);
2358 return NULL;
2359 }
2360
2361 memcpy(newdata, data, *size - 1);
2362 newdata[*size] = '\0';
2363
2364 msi_free(data);
2365 data = (LPSTR)newdata;
2366 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002367 }
2368 return data;
2369}
2370
Aric Stewart92ef78e2005-06-21 20:21:18 +00002371static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2372{
2373 MSIPACKAGE *package = (MSIPACKAGE*)param;
2374 static const WCHAR szHCR[] =
2375 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2376 'R','O','O','T','\\',0};
2377 static const WCHAR szHCU[] =
2378 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2379 'U','S','E','R','\\',0};
2380 static const WCHAR szHLM[] =
2381 {'H','K','E','Y','_','L','O','C','A','L','_',
2382 'M','A','C','H','I','N','E','\\',0};
2383 static const WCHAR szHU[] =
2384 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2385
2386 LPSTR value_data = NULL;
2387 HKEY root_key, hkey;
2388 DWORD type,size;
2389 LPWSTR deformated;
2390 LPCWSTR szRoot, component, name, key, value;
Mike McCormack38d67a42005-08-22 09:15:23 +00002391 MSICOMPONENT *comp;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002392 MSIRECORD * uirow;
2393 LPWSTR uikey;
2394 INT root;
2395 BOOL check_first = FALSE;
2396 UINT rc;
2397
2398 ui_progress(package,2,0,0,0);
2399
2400 value = NULL;
2401 key = NULL;
2402 uikey = NULL;
2403 name = NULL;
2404
2405 component = MSI_RecordGetString(row, 6);
Mike McCormack38d67a42005-08-22 09:15:23 +00002406 comp = get_loaded_component(package,component);
Johan Dahlin0946c422005-08-24 10:57:27 +00002407 if (!comp)
2408 return ERROR_SUCCESS;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002409
Mike McCormackd693f462005-10-29 11:36:48 +00002410 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewart92ef78e2005-06-21 20:21:18 +00002411 {
2412 TRACE("Skipping write due to disabled component %s\n",
2413 debugstr_w(component));
2414
Mike McCormack38d67a42005-08-22 09:15:23 +00002415 comp->Action = comp->Installed;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002416
2417 return ERROR_SUCCESS;
2418 }
2419
Mike McCormack38d67a42005-08-22 09:15:23 +00002420 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002421
2422 name = MSI_RecordGetString(row, 4);
2423 if( MSI_RecordIsNull(row,5) && name )
2424 {
2425 /* null values can have special meanings */
2426 if (name[0]=='-' && name[1] == 0)
2427 return ERROR_SUCCESS;
2428 else if ((name[0]=='+' && name[1] == 0) ||
2429 (name[0] == '*' && name[1] == 0))
2430 name = NULL;
2431 check_first = TRUE;
2432 }
2433
2434 root = MSI_RecordGetInteger(row,2);
2435 key = MSI_RecordGetString(row, 3);
2436
2437 /* get the root key */
2438 switch (root)
2439 {
Aric Stewart0713f092005-06-24 11:51:29 +00002440 case -1:
2441 {
2442 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
Mike McCormack062ad502005-09-15 15:04:08 +00002443 LPWSTR all_users = msi_dup_property( package, szALLUSER );
Aric Stewart0713f092005-06-24 11:51:29 +00002444 if (all_users && all_users[0] == '1')
2445 {
2446 root_key = HKEY_LOCAL_MACHINE;
2447 szRoot = szHLM;
2448 }
2449 else
2450 {
2451 root_key = HKEY_CURRENT_USER;
2452 szRoot = szHCU;
2453 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002454 msi_free(all_users);
Aric Stewart0713f092005-06-24 11:51:29 +00002455 }
2456 break;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002457 case 0: root_key = HKEY_CLASSES_ROOT;
2458 szRoot = szHCR;
2459 break;
2460 case 1: root_key = HKEY_CURRENT_USER;
2461 szRoot = szHCU;
2462 break;
2463 case 2: root_key = HKEY_LOCAL_MACHINE;
2464 szRoot = szHLM;
2465 break;
2466 case 3: root_key = HKEY_USERS;
2467 szRoot = szHU;
2468 break;
2469 default:
2470 ERR("Unknown root %i\n",root);
2471 root_key=NULL;
2472 szRoot = NULL;
2473 break;
2474 }
2475 if (!root_key)
2476 return ERROR_SUCCESS;
2477
2478 deformat_string(package, key , &deformated);
2479 size = strlenW(deformated) + strlenW(szRoot) + 1;
Mike McCormackee034ba2005-09-20 11:59:14 +00002480 uikey = msi_alloc(size*sizeof(WCHAR));
Aric Stewart92ef78e2005-06-21 20:21:18 +00002481 strcpyW(uikey,szRoot);
2482 strcatW(uikey,deformated);
2483
2484 if (RegCreateKeyW( root_key, deformated, &hkey))
2485 {
2486 ERR("Could not create key %s\n",debugstr_w(deformated));
Mike McCormackee034ba2005-09-20 11:59:14 +00002487 msi_free(deformated);
2488 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002489 return ERROR_SUCCESS;
2490 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002491 msi_free(deformated);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002492
2493 value = MSI_RecordGetString(row,5);
2494 if (value)
2495 value_data = parse_value(package, value, &type, &size);
2496 else
2497 {
2498 static const WCHAR szEmpty[] = {0};
2499 value_data = (LPSTR)strdupW(szEmpty);
2500 size = 0;
2501 type = REG_SZ;
2502 }
2503
2504 deformat_string(package, name, &deformated);
2505
2506 /* get the double nulls to terminate SZ_MULTI */
2507 if (type == REG_MULTI_SZ)
2508 size +=sizeof(WCHAR);
2509
2510 if (!check_first)
2511 {
2512 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2513 debugstr_w(uikey));
Mike McCormack16466af2005-07-06 10:33:30 +00002514 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002515 }
2516 else
2517 {
2518 DWORD sz = 0;
2519 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2520 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2521 {
2522 TRACE("value %s of %s checked already exists\n",
2523 debugstr_w(deformated), debugstr_w(uikey));
2524 }
2525 else
2526 {
2527 TRACE("Checked and setting value %s of %s\n",
2528 debugstr_w(deformated), debugstr_w(uikey));
2529 if (deformated || size)
Mike McCormack16466af2005-07-06 10:33:30 +00002530 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002531 }
2532 }
2533 RegCloseKey(hkey);
2534
2535 uirow = MSI_CreateRecord(3);
2536 MSI_RecordSetStringW(uirow,2,deformated);
2537 MSI_RecordSetStringW(uirow,1,uikey);
2538
2539 if (type == REG_SZ)
2540 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2541 else
2542 MSI_RecordSetStringW(uirow,3,value);
2543
2544 ui_actiondata(package,szWriteRegistryValues,uirow);
2545 msiobj_release( &uirow->hdr );
2546
Mike McCormackee034ba2005-09-20 11:59:14 +00002547 msi_free(value_data);
2548 msi_free(deformated);
2549 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002550
2551 return ERROR_SUCCESS;
2552}
2553
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002554static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00002555{
2556 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002557 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002558 static const WCHAR ExecSeqQuery[] =
2559 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002560 '`','R','e','g','i','s','t','r','y','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00002561
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002562 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002563 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002564 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00002565
Aric Stewartd2c395a2004-07-06 18:48:15 +00002566 /* increment progress bar each time action data is sent */
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002567 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002568
Aric Stewart92ef78e2005-06-21 20:21:18 +00002569 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002570
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002571 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002572 return rc;
2573}
2574
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002575static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002576{
Aric Stewart9cd707d2005-05-27 19:24:22 +00002577 package->script->CurrentlyScripting = TRUE;
2578
Aric Stewart7d3e5972004-07-04 00:36:58 +00002579 return ERROR_SUCCESS;
2580}
2581
Aric Stewartae1aa322004-12-27 19:02:59 +00002582
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002583static UINT ACTION_InstallValidate(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002584{
Mike McCormack38d67a42005-08-22 09:15:23 +00002585 MSICOMPONENT *comp;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002586 DWORD progress = 0;
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002587 DWORD total = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002588 static const WCHAR q1[]=
2589 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002590 '`','R','e','g','i','s','t','r','y','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002591 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002592 MSIQUERY * view;
Mike McCormack1da28582005-08-22 14:09:17 +00002593 MSIFEATURE *feature;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002594 MSIFILE *file;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002595
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002596 TRACE("InstallValidate\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002597
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002598 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002599 if (rc == ERROR_SUCCESS)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002600 {
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002601 MSI_IterateRecords( view, &progress, NULL, package );
2602 msiobj_release( &view->hdr );
2603 total += progress * REG_PROGRESS_VALUE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002604 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002605
Mike McCormack38d67a42005-08-22 09:15:23 +00002606 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Mike McCormack38d67a42005-08-22 09:15:23 +00002607 total += COMPONENT_PROGRESS_VALUE;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002608
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002609 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002610 total += file->FileSize;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002611
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002612 ui_progress(package,0,total,0,0);
Aric Stewart7d3e5972004-07-04 00:36:58 +00002613
Mike McCormack1da28582005-08-22 14:09:17 +00002614 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002615 {
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002616 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2617 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2618 feature->ActionRequest);
2619 }
2620
Aric Stewart7d3e5972004-07-04 00:36:58 +00002621 return ERROR_SUCCESS;
2622}
2623
Aric Stewartc79f4e22005-06-22 18:03:08 +00002624static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2625{
2626 MSIPACKAGE* package = (MSIPACKAGE*)param;
2627 LPCWSTR cond = NULL;
2628 LPCWSTR message = NULL;
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002629 UINT r;
2630
Aric Stewartc79f4e22005-06-22 18:03:08 +00002631 static const WCHAR title[]=
2632 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2633
2634 cond = MSI_RecordGetString(row,1);
2635
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002636 r = MSI_EvaluateConditionW(package,cond);
2637 if (r == MSICONDITION_FALSE)
Aric Stewartc79f4e22005-06-22 18:03:08 +00002638 {
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002639 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2640 {
2641 LPWSTR deformated;
2642 message = MSI_RecordGetString(row,2);
2643 deformat_string(package,message,&deformated);
2644 MessageBoxW(NULL,deformated,title,MB_OK);
2645 msi_free(deformated);
2646 }
2647
2648 return ERROR_INSTALL_FAILURE;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002649 }
2650
2651 return ERROR_SUCCESS;
2652}
2653
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002654static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
Aric Stewart5b936ca2004-07-06 18:47:09 +00002655{
2656 UINT rc;
Mike McCormackf3c8b832004-07-19 19:35:05 +00002657 MSIQUERY * view = NULL;
Aric Stewart8e233e92005-03-01 11:45:19 +00002658 static const WCHAR ExecSeqQuery[] =
2659 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002660 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002661
Aric Stewart5b936ca2004-07-06 18:47:09 +00002662 TRACE("Checking launch conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002663
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002664 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart5b936ca2004-07-06 18:47:09 +00002665 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002666 return ERROR_SUCCESS;
Aric Stewart5b936ca2004-07-06 18:47:09 +00002667
Aric Stewartc79f4e22005-06-22 18:03:08 +00002668 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002669 msiobj_release(&view->hdr);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002670
Aric Stewart5b936ca2004-07-06 18:47:09 +00002671 return rc;
2672}
Aric Stewart7d3e5972004-07-04 00:36:58 +00002673
Mike McCormack38d67a42005-08-22 09:15:23 +00002674static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
Aric Stewartb942e182004-07-06 18:50:02 +00002675{
Aric Stewartb942e182004-07-06 18:50:02 +00002676
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002677 if (!cmp->KeyPath)
James Hawkins8cedb212007-03-29 02:38:57 -05002678 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002679
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002680 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
Aric Stewartb942e182004-07-06 18:50:02 +00002681 {
Aric Stewart6269f002005-01-17 13:40:39 +00002682 MSIRECORD * row = 0;
Mike McCormack0b352c72005-06-02 10:29:57 +00002683 UINT root,len;
Aric Stewart09b0aba2005-06-09 20:30:59 +00002684 LPWSTR deformated,buffer,deformated_name;
2685 LPCWSTR key,name;
Aric Stewart8e233e92005-03-01 11:45:19 +00002686 static const WCHAR ExecSeqQuery[] =
2687 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002688 '`','R','e','g','i','s','t','r','y','`',' ',
2689 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2690 ' ','=',' ' ,'\'','%','s','\'',0 };
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002691 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00002692 static const WCHAR fmt2[]=
2693 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
Aric Stewart6269f002005-01-17 13:40:39 +00002694
Mike McCormack0b352c72005-06-02 10:29:57 +00002695 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2696 if (!row)
Aric Stewart6269f002005-01-17 13:40:39 +00002697 return NULL;
2698
Aric Stewart6269f002005-01-17 13:40:39 +00002699 root = MSI_RecordGetInteger(row,2);
Aric Stewart09b0aba2005-06-09 20:30:59 +00002700 key = MSI_RecordGetString(row, 3);
2701 name = MSI_RecordGetString(row, 4);
Aric Stewart6269f002005-01-17 13:40:39 +00002702 deformat_string(package, key , &deformated);
2703 deformat_string(package, name, &deformated_name);
2704
Ulrich Czekallae15e5172005-03-08 16:44:51 +00002705 len = strlenW(deformated) + 6;
Aric Stewart6269f002005-01-17 13:40:39 +00002706 if (deformated_name)
2707 len+=strlenW(deformated_name);
2708
Mike McCormackee034ba2005-09-20 11:59:14 +00002709 buffer = msi_alloc( len *sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00002710
2711 if (deformated_name)
2712 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2713 else
2714 sprintfW(buffer,fmt,root,deformated);
2715
Mike McCormackee034ba2005-09-20 11:59:14 +00002716 msi_free(deformated);
2717 msi_free(deformated_name);
Aric Stewart6269f002005-01-17 13:40:39 +00002718 msiobj_release(&row->hdr);
Aric Stewart6269f002005-01-17 13:40:39 +00002719
2720 return buffer;
2721 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002722 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewart6269f002005-01-17 13:40:39 +00002723 {
2724 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
Aric Stewartfa384f62004-12-22 18:46:17 +00002725 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002726 }
2727 else
2728 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002729 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
Aric Stewartfcb20c52004-07-06 18:51:16 +00002730
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002731 if (file)
2732 return strdupW( file->TargetPath );
Aric Stewartb942e182004-07-06 18:50:02 +00002733 }
Aric Stewartfa384f62004-12-22 18:46:17 +00002734 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002735}
2736
Stefan Huehnerac6f5622005-06-20 14:18:03 +00002737static HKEY openSharedDLLsKey(void)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002738{
2739 HKEY hkey=0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002740 static const WCHAR path[] =
2741 {'S','o','f','t','w','a','r','e','\\',
2742 'M','i','c','r','o','s','o','f','t','\\',
2743 'W','i','n','d','o','w','s','\\',
2744 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2745 'S','h','a','r','e','d','D','L','L','s',0};
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002746
2747 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2748 return hkey;
2749}
2750
2751static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2752{
2753 HKEY hkey;
2754 DWORD count=0;
2755 DWORD type;
2756 DWORD sz = sizeof(count);
2757 DWORD rc;
2758
2759 hkey = openSharedDLLsKey();
2760 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2761 if (rc != ERROR_SUCCESS)
2762 count = 0;
2763 RegCloseKey(hkey);
2764 return count;
2765}
2766
2767static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2768{
2769 HKEY hkey;
2770
2771 hkey = openSharedDLLsKey();
2772 if (count > 0)
Mike McCormack4db02cd2005-09-15 14:58:38 +00002773 msi_reg_set_val_dword( hkey, path, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002774 else
2775 RegDeleteValueW(hkey,path);
2776 RegCloseKey(hkey);
2777 return count;
2778}
2779
2780/*
2781 * Return TRUE if the count should be written out and FALSE if not
2782 */
Mike McCormack38d67a42005-08-22 09:15:23 +00002783static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002784{
Mike McCormack1da28582005-08-22 14:09:17 +00002785 MSIFEATURE *feature;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002786 INT count = 0;
2787 BOOL write = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002788
2789 /* only refcount DLLs */
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002790 if (comp->KeyPath == NULL ||
Mike McCormack38d67a42005-08-22 09:15:23 +00002791 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2792 comp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002793 write = FALSE;
2794 else
2795 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002796 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002797 write = (count > 0);
2798
Mike McCormack38d67a42005-08-22 09:15:23 +00002799 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002800 write = TRUE;
2801 }
2802
2803 /* increment counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002805 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002806 ComponentList *cl;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002807
Mike McCormack1da28582005-08-22 14:09:17 +00002808 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002809 continue;
2810
Mike McCormack1da28582005-08-22 14:09:17 +00002811 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002812 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002813 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002814 count++;
2815 }
2816 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002817
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002818 /* decrement counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002819 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002820 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002821 ComponentList *cl;
2822
Mike McCormack1da28582005-08-22 14:09:17 +00002823 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002824 continue;
2825
Mike McCormack1da28582005-08-22 14:09:17 +00002826 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002827 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002828 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002829 count--;
2830 }
2831 }
2832
2833 /* ref count all the files in the component */
2834 if (write)
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002835 {
2836 MSIFILE *file;
2837
2838 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002839 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002840 if (file->Component == comp)
2841 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002842 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002843 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002844
2845 /* add a count for permenent */
Mike McCormack38d67a42005-08-22 09:15:23 +00002846 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002847 count ++;
2848
Mike McCormack38d67a42005-08-22 09:15:23 +00002849 comp->RefCount = count;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002850
2851 if (write)
Mike McCormack38d67a42005-08-22 09:15:23 +00002852 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002853}
2854
Aric Stewart2cf222f2004-07-06 19:00:23 +00002855/*
2856 * Ok further analysis makes me think that this work is
2857 * actually done in the PublishComponents and PublishFeatures
Mike McCormack3ece2462004-07-09 19:33:25 +00002858 * step, and not here. It appears like the keypath and all that is
2859 * resolved in this step, however actually written in the Publish steps.
Alexandre Julliard77b12762004-07-09 19:43:29 +00002860 * But we will leave it here for now because it is unclear
Aric Stewart2cf222f2004-07-06 19:00:23 +00002861 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002862static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
Aric Stewartb942e182004-07-06 18:50:02 +00002863{
Aric Stewart68b07492005-01-25 11:05:37 +00002864 WCHAR squished_pc[GUID_SIZE];
2865 WCHAR squished_cc[GUID_SIZE];
Aric Stewartb942e182004-07-06 18:50:02 +00002866 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00002867 MSICOMPONENT *comp;
Aric Stewart68b07492005-01-25 11:05:37 +00002868 HKEY hkey=0,hkey2=0;
Aric Stewartb942e182004-07-06 18:50:02 +00002869
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002870 TRACE("\n");
2871
Aric Stewartb942e182004-07-06 18:50:02 +00002872 /* writes the Component and Features values to the registry */
Aric Stewartb942e182004-07-06 18:50:02 +00002873
Aric Stewart68b07492005-01-25 11:05:37 +00002874 rc = MSIREG_OpenComponents(&hkey);
Aric Stewartb942e182004-07-06 18:50:02 +00002875 if (rc != ERROR_SUCCESS)
Mike McCormackfe8cd382006-03-09 14:21:37 +09002876 return rc;
2877
Aric Stewartadaef112005-07-07 20:27:06 +00002878 squash_guid(package->ProductCode,squished_pc);
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002879 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
Mike McCormack38d67a42005-08-22 09:15:23 +00002880
2881 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewartb942e182004-07-06 18:50:02 +00002882 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002883 MSIRECORD * uirow;
2884
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002885 ui_progress(package,2,0,0,0);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002886 if (!comp->ComponentId)
2887 continue;
Aric Stewartb942e182004-07-06 18:50:02 +00002888
Mike McCormackfe8cd382006-03-09 14:21:37 +09002889 squash_guid(comp->ComponentId,squished_cc);
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002890
Mike McCormackfe8cd382006-03-09 14:21:37 +09002891 msi_free(comp->FullKeypath);
2892 comp->FullKeypath = resolve_keypath( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002893
Mike McCormackfe8cd382006-03-09 14:21:37 +09002894 /* do the refcounting */
2895 ACTION_RefCountComponent( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002896
Mike McCormackfe8cd382006-03-09 14:21:37 +09002897 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
Mike McCormack38d67a42005-08-22 09:15:23 +00002898 debugstr_w(comp->Component),
Aric Stewartc5a14432005-05-18 17:46:12 +00002899 debugstr_w(squished_cc),
Mike McCormackfe8cd382006-03-09 14:21:37 +09002900 debugstr_w(comp->FullKeypath),
Mike McCormack38d67a42005-08-22 09:15:23 +00002901 comp->RefCount);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002902 /*
2903 * Write the keypath out if the component is to be registered
2904 * and delete the key if the component is to be deregistered
2905 */
2906 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2907 {
2908 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2909 if (rc != ERROR_SUCCESS)
2910 continue;
2911
2912 if (!comp->FullKeypath)
2913 continue;
2914
2915 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2916
2917 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartfa384f62004-12-22 18:46:17 +00002918 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002919 static const WCHAR szPermKey[] =
2920 { '0','0','0','0','0','0','0','0','0','0','0','0',
2921 '0','0','0','0','0','0','0','0','0','0','0','0',
2922 '0','0','0','0','0','0','0','0',0 };
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002923
Mike McCormackfe8cd382006-03-09 14:21:37 +09002924 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002925 }
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002926
Mike McCormackfe8cd382006-03-09 14:21:37 +09002927 RegCloseKey(hkey2);
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002928
2929 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, &hkey2, TRUE);
2930 if (rc != ERROR_SUCCESS)
2931 continue;
2932
2933 msi_reg_set_val_str(hkey2, squished_pc, comp->FullKeypath);
2934 RegCloseKey(hkey2);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002935 }
2936 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2937 {
2938 DWORD res;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002939
Mike McCormackfe8cd382006-03-09 14:21:37 +09002940 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2941 if (rc != ERROR_SUCCESS)
2942 continue;
2943
2944 RegDeleteValueW(hkey2,squished_pc);
2945
2946 /* if the key is empty delete it */
2947 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2948 RegCloseKey(hkey2);
2949 if (res == ERROR_NO_MORE_ITEMS)
2950 RegDeleteKeyW(hkey,squished_cc);
2951
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002952 MSIREG_DeleteUserDataComponentKey(comp->ComponentId);
Aric Stewartb942e182004-07-06 18:50:02 +00002953 }
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002954
2955 /* UI stuff */
2956 uirow = MSI_CreateRecord(3);
2957 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2958 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2959 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2960 ui_actiondata(package,szProcessComponents,uirow);
2961 msiobj_release( &uirow->hdr );
2962 }
Aric Stewartb942e182004-07-06 18:50:02 +00002963 RegCloseKey(hkey);
2964 return rc;
2965}
2966
Aric Stewart6e821732005-03-30 10:19:08 +00002967typedef struct {
2968 CLSID clsid;
2969 LPWSTR source;
2970
2971 LPWSTR path;
2972 ITypeLib *ptLib;
2973} typelib_struct;
2974
Mike McCormackf9acfe62005-06-07 20:29:51 +00002975static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
Aric Stewart6e821732005-03-30 10:19:08 +00002976 LPWSTR lpszName, LONG_PTR lParam)
2977{
2978 TLIBATTR *attr;
2979 typelib_struct *tl_struct = (typelib_struct*) lParam;
2980 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2981 int sz;
2982 HRESULT res;
2983
2984 if (!IS_INTRESOURCE(lpszName))
2985 {
2986 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2987 return TRUE;
2988 }
2989
2990 sz = strlenW(tl_struct->source)+4;
2991 sz *= sizeof(WCHAR);
2992
Mike McCormack2acf8002006-05-25 11:41:39 +09002993 if ((INT_PTR)lpszName == 1)
Aric Stewartca8c4e42005-06-02 15:13:57 +00002994 tl_struct->path = strdupW(tl_struct->source);
2995 else
2996 {
Mike McCormackee034ba2005-09-20 11:59:14 +00002997 tl_struct->path = msi_alloc(sz);
Aric Stewartca8c4e42005-06-02 15:13:57 +00002998 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2999 }
Aric Stewart6e821732005-03-30 10:19:08 +00003000
3001 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3002 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3003 if (!SUCCEEDED(res))
3004 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003005 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003006 tl_struct->path = NULL;
3007
3008 return TRUE;
3009 }
3010
3011 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3012 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3013 {
3014 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3015 return FALSE;
3016 }
3017
Mike McCormackee034ba2005-09-20 11:59:14 +00003018 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003019 tl_struct->path = NULL;
3020
3021 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3022 ITypeLib_Release(tl_struct->ptLib);
3023
3024 return TRUE;
3025}
3026
Aric Stewart234dc4b2005-06-22 18:27:34 +00003027static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3028{
3029 MSIPACKAGE* package = (MSIPACKAGE*)param;
3030 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00003031 MSICOMPONENT *comp;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003032 MSIFILE *file;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003033 typelib_struct tl_struct;
3034 HMODULE module;
3035 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
3036
3037 component = MSI_RecordGetString(row,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00003038 comp = get_loaded_component(package,component);
3039 if (!comp)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003040 return ERROR_SUCCESS;
3041
Mike McCormackd693f462005-10-29 11:36:48 +00003042 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewart234dc4b2005-06-22 18:27:34 +00003043 {
3044 TRACE("Skipping typelib reg due to disabled component\n");
3045
Mike McCormack38d67a42005-08-22 09:15:23 +00003046 comp->Action = comp->Installed;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003047
3048 return ERROR_SUCCESS;
3049 }
3050
Mike McCormack38d67a42005-08-22 09:15:23 +00003051 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003052
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003053 file = get_loaded_file( package, comp->KeyPath );
3054 if (!file)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003055 return ERROR_SUCCESS;
3056
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003057 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
Mike McCormack51c66182005-10-27 12:36:12 +00003058 if (module)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003059 {
Mike McCormack51c66182005-10-27 12:36:12 +00003060 LPCWSTR guid;
3061 guid = MSI_RecordGetString(row,1);
3062 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003063 tl_struct.source = strdupW( file->TargetPath );
Aric Stewart234dc4b2005-06-22 18:27:34 +00003064 tl_struct.path = NULL;
3065
3066 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3067 (LONG_PTR)&tl_struct);
3068
Mike McCormack51c66182005-10-27 12:36:12 +00003069 if (tl_struct.path)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003070 {
3071 LPWSTR help = NULL;
3072 LPCWSTR helpid;
3073 HRESULT res;
3074
3075 helpid = MSI_RecordGetString(row,6);
3076
3077 if (helpid)
James Hawkins8cedb212007-03-29 02:38:57 -05003078 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003079 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
Mike McCormackee034ba2005-09-20 11:59:14 +00003080 msi_free(help);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003081
3082 if (!SUCCEEDED(res))
3083 ERR("Failed to register type library %s\n",
3084 debugstr_w(tl_struct.path));
3085 else
3086 {
3087 ui_actiondata(package,szRegisterTypeLibraries,row);
3088
3089 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3090 }
3091
3092 ITypeLib_Release(tl_struct.ptLib);
Mike McCormackee034ba2005-09-20 11:59:14 +00003093 msi_free(tl_struct.path);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003094 }
3095 else
3096 ERR("Failed to load type library %s\n",
3097 debugstr_w(tl_struct.source));
3098
3099 FreeLibrary(module);
Mike McCormackee034ba2005-09-20 11:59:14 +00003100 msi_free(tl_struct.source);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003101 }
3102 else
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003103 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
Aric Stewart234dc4b2005-06-22 18:27:34 +00003104
3105 return ERROR_SUCCESS;
3106}
3107
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003108static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
Aric Stewartfcb20c52004-07-06 18:51:16 +00003109{
3110 /*
Mike McCormackc90c7812004-07-09 22:58:27 +00003111 * OK this is a bit confusing.. I am given a _Component key and I believe
Aric Stewartfcb20c52004-07-06 18:51:16 +00003112 * that the file that is being registered as a type library is the "key file
Mike McCormackc90c7812004-07-09 22:58:27 +00003113 * of that component" which I interpret to mean "The file in the KeyPath of
3114 * that component".
Aric Stewartfcb20c52004-07-06 18:51:16 +00003115 */
3116 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003117 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003118 static const WCHAR Query[] =
3119 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003120 '`','T','y','p','e','L','i','b','`',0};
Aric Stewartfcb20c52004-07-06 18:51:16 +00003121
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003122 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003123 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00003124 return ERROR_SUCCESS;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003125
Aric Stewart234dc4b2005-06-22 18:27:34 +00003126 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003127 msiobj_release(&view->hdr);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003128 return rc;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003129}
3130
Aric Stewart9adacf62005-06-24 11:58:21 +00003131static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003132{
Aric Stewart9adacf62005-06-24 11:58:21 +00003133 MSIPACKAGE *package = (MSIPACKAGE*)param;
Mike McCormack477bce32006-01-16 20:38:28 +01003134 LPWSTR target_file, target_folder, filename;
Robert Shearman4ac85672006-02-22 16:31:00 +00003135 LPCWSTR buffer, extension;
Mike McCormack38d67a42005-08-22 09:15:23 +00003136 MSICOMPONENT *comp;
Aric Stewart9adacf62005-06-24 11:58:21 +00003137 static const WCHAR szlnk[]={'.','l','n','k',0};
Mike McCormack20c57462006-05-24 17:41:04 +09003138 IShellLinkW *sl = NULL;
3139 IPersistFile *pf = NULL;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003140 HRESULT res;
3141
Aric Stewart9adacf62005-06-24 11:58:21 +00003142 buffer = MSI_RecordGetString(row,4);
Mike McCormack38d67a42005-08-22 09:15:23 +00003143 comp = get_loaded_component(package,buffer);
3144 if (!comp)
Aric Stewart9adacf62005-06-24 11:58:21 +00003145 return ERROR_SUCCESS;
3146
Mike McCormackd693f462005-10-29 11:36:48 +00003147 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003148 {
3149 TRACE("Skipping shortcut creation due to disabled component\n");
3150
Mike McCormack38d67a42005-08-22 09:15:23 +00003151 comp->Action = comp->Installed;
Aric Stewart9adacf62005-06-24 11:58:21 +00003152
3153 return ERROR_SUCCESS;
3154 }
3155
Mike McCormack38d67a42005-08-22 09:15:23 +00003156 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart9adacf62005-06-24 11:58:21 +00003157
3158 ui_actiondata(package,szCreateShortcuts,row);
3159
3160 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3161 &IID_IShellLinkW, (LPVOID *) &sl );
3162
Mike McCormack20c57462006-05-24 17:41:04 +09003163 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003164 {
Mike McCormack20c57462006-05-24 17:41:04 +09003165 ERR("CLSID_ShellLink not available\n");
3166 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003167 }
3168
3169 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
Mike McCormack20c57462006-05-24 17:41:04 +09003170 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003171 {
Mike McCormack20c57462006-05-24 17:41:04 +09003172 ERR("QueryInterface(IID_IPersistFile) failed\n");
3173 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003174 }
3175
3176 buffer = MSI_RecordGetString(row,2);
James Hawkins8cedb212007-03-29 02:38:57 -05003177 target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
Aric Stewart9adacf62005-06-24 11:58:21 +00003178
3179 /* may be needed because of a bug somehwere else */
3180 create_full_pathW(target_folder);
3181
Mike McCormack477bce32006-01-16 20:38:28 +01003182 filename = msi_dup_record_field( row, 3 );
Aric Stewart9adacf62005-06-24 11:58:21 +00003183 reduce_to_longfilename(filename);
Robert Shearman4ac85672006-02-22 16:31:00 +00003184
3185 extension = strchrW(filename,'.');
3186 if (!extension || strcmpiW(extension,szlnk))
3187 {
3188 int len = strlenW(filename);
3189 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3190 memcpy(filename + len, szlnk, sizeof(szlnk));
3191 }
Aric Stewart9adacf62005-06-24 11:58:21 +00003192 target_file = build_directory_name(2, target_folder, filename);
Mike McCormackee034ba2005-09-20 11:59:14 +00003193 msi_free(target_folder);
Mike McCormack477bce32006-01-16 20:38:28 +01003194 msi_free(filename);
Aric Stewart9adacf62005-06-24 11:58:21 +00003195
3196 buffer = MSI_RecordGetString(row,5);
3197 if (strchrW(buffer,'['))
3198 {
3199 LPWSTR deformated;
3200 deformat_string(package,buffer,&deformated);
3201 IShellLinkW_SetPath(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003202 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003203 }
3204 else
3205 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003206 FIXME("poorly handled shortcut format, advertised shortcut\n");
Mike McCormack566c69e2005-09-22 10:49:17 +00003207 IShellLinkW_SetPath(sl,comp->FullKeypath);
Aric Stewart9adacf62005-06-24 11:58:21 +00003208 }
3209
3210 if (!MSI_RecordIsNull(row,6))
3211 {
3212 LPWSTR deformated;
3213 buffer = MSI_RecordGetString(row,6);
3214 deformat_string(package,buffer,&deformated);
3215 IShellLinkW_SetArguments(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003216 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003217 }
3218
3219 if (!MSI_RecordIsNull(row,7))
3220 {
3221 buffer = MSI_RecordGetString(row,7);
3222 IShellLinkW_SetDescription(sl,buffer);
3223 }
3224
3225 if (!MSI_RecordIsNull(row,8))
3226 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3227
3228 if (!MSI_RecordIsNull(row,9))
3229 {
Mike McCormack75658d72005-09-22 10:33:57 +00003230 LPWSTR Path;
Aric Stewart9adacf62005-06-24 11:58:21 +00003231 INT index;
3232
3233 buffer = MSI_RecordGetString(row,9);
3234
Mike McCormack75658d72005-09-22 10:33:57 +00003235 Path = build_icon_path(package,buffer);
Aric Stewart9adacf62005-06-24 11:58:21 +00003236 index = MSI_RecordGetInteger(row,10);
3237
Robert Shearmanab378802006-08-03 20:24:10 +01003238 /* no value means 0 */
3239 if (index == MSI_NULL_INTEGER)
3240 index = 0;
3241
Aric Stewart9adacf62005-06-24 11:58:21 +00003242 IShellLinkW_SetIconLocation(sl,Path,index);
Mike McCormackee034ba2005-09-20 11:59:14 +00003243 msi_free(Path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003244 }
3245
3246 if (!MSI_RecordIsNull(row,11))
3247 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3248
3249 if (!MSI_RecordIsNull(row,12))
3250 {
3251 LPWSTR Path;
3252 buffer = MSI_RecordGetString(row,12);
James Hawkins8cedb212007-03-29 02:38:57 -05003253 Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
Mike McCormack43f7f3e2006-07-27 23:18:15 +09003254 if (Path)
3255 IShellLinkW_SetWorkingDirectory(sl,Path);
Mike McCormackee034ba2005-09-20 11:59:14 +00003256 msi_free(Path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003257 }
3258
3259 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3260 IPersistFile_Save(pf,target_file,FALSE);
3261
Mike McCormackee034ba2005-09-20 11:59:14 +00003262 msi_free(target_file);
Aric Stewart9adacf62005-06-24 11:58:21 +00003263
Mike McCormack20c57462006-05-24 17:41:04 +09003264err:
3265 if (pf)
3266 IPersistFile_Release( pf );
3267 if (sl)
3268 IShellLinkW_Release( sl );
Aric Stewart9adacf62005-06-24 11:58:21 +00003269
3270 return ERROR_SUCCESS;
3271}
3272
3273static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3274{
3275 UINT rc;
3276 HRESULT res;
3277 MSIQUERY * view;
3278 static const WCHAR Query[] =
3279 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3280 '`','S','h','o','r','t','c','u','t','`',0};
3281
Aric Stewart9adacf62005-06-24 11:58:21 +00003282 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3283 if (rc != ERROR_SUCCESS)
3284 return ERROR_SUCCESS;
3285
Aric Stewart2cf222f2004-07-06 19:00:23 +00003286 res = CoInitialize( NULL );
3287 if (FAILED (res))
3288 {
3289 ERR("CoInitialize failed\n");
3290 return ERROR_FUNCTION_FAILED;
3291 }
3292
Aric Stewart9adacf62005-06-24 11:58:21 +00003293 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003294 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003295
Aric Stewart2cf222f2004-07-06 19:00:23 +00003296 CoUninitialize();
3297
3298 return rc;
3299}
3300
Aric Stewart916ef942005-06-22 18:42:19 +00003301static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3302{
3303 MSIPACKAGE* package = (MSIPACKAGE*)param;
3304 HANDLE the_file;
Mike McCormack75658d72005-09-22 10:33:57 +00003305 LPWSTR FilePath;
3306 LPCWSTR FileName;
Aric Stewart916ef942005-06-22 18:42:19 +00003307 CHAR buffer[1024];
3308 DWORD sz;
3309 UINT rc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003310 MSIRECORD *uirow;
Aric Stewart916ef942005-06-22 18:42:19 +00003311
3312 FileName = MSI_RecordGetString(row,1);
3313 if (!FileName)
3314 {
3315 ERR("Unable to get FileName\n");
3316 return ERROR_SUCCESS;
3317 }
3318
Mike McCormack75658d72005-09-22 10:33:57 +00003319 FilePath = build_icon_path(package,FileName);
Aric Stewart916ef942005-06-22 18:42:19 +00003320
3321 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3322
3323 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3324 FILE_ATTRIBUTE_NORMAL, NULL);
3325
3326 if (the_file == INVALID_HANDLE_VALUE)
3327 {
3328 ERR("Unable to create file %s\n",debugstr_w(FilePath));
Mike McCormackee034ba2005-09-20 11:59:14 +00003329 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003330 return ERROR_SUCCESS;
3331 }
3332
3333 do
3334 {
3335 DWORD write;
3336 sz = 1024;
3337 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3338 if (rc != ERROR_SUCCESS)
3339 {
3340 ERR("Failed to get stream\n");
3341 CloseHandle(the_file);
3342 DeleteFileW(FilePath);
3343 break;
3344 }
3345 WriteFile(the_file,buffer,sz,&write,NULL);
3346 } while (sz == 1024);
3347
Mike McCormackee034ba2005-09-20 11:59:14 +00003348 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003349
3350 CloseHandle(the_file);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003351
3352 uirow = MSI_CreateRecord(1);
3353 MSI_RecordSetStringW(uirow,1,FileName);
3354 ui_actiondata(package,szPublishProduct,uirow);
3355 msiobj_release( &uirow->hdr );
3356
Aric Stewart916ef942005-06-22 18:42:19 +00003357 return ERROR_SUCCESS;
3358}
Aric Stewart2cf222f2004-07-06 19:00:23 +00003359
James Hawkinsa2df31a2007-07-02 20:21:26 -07003360static BOOL msi_check_publish(MSIPACKAGE *package)
3361{
3362 MSIFEATURE *feature;
3363
3364 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3365 {
3366 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3367 return TRUE;
3368 }
3369
3370 return FALSE;
3371}
3372
Aric Stewart2cf222f2004-07-06 19:00:23 +00003373/*
3374 * 99% of the work done here is only done for
3375 * advertised installs. However this is where the
3376 * Icon table is processed and written out
Francois Gouget817c5202004-07-16 19:15:40 +00003377 * so that is what I am going to do here.
Aric Stewart2cf222f2004-07-06 19:00:23 +00003378 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003379static UINT ACTION_PublishProduct(MSIPACKAGE *package)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003380{
3381 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003382 MSIQUERY * view;
James Hawkins5e46fc92007-07-02 20:20:20 -07003383 MSISOURCELISTINFO *info;
3384 MSIMEDIADISK *disk;
Aric Stewart8e233e92005-03-01 11:45:19 +00003385 static const WCHAR Query[]=
3386 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003387 '`','I','c','o','n','`',0};
Aric Stewart6269f002005-01-17 13:40:39 +00003388 /* for registry stuff */
Aric Stewart68b07492005-01-25 11:05:37 +00003389 HKEY hkey=0;
3390 HKEY hukey=0;
James Hawkinsc18b7752007-06-26 19:22:46 -07003391 HKEY hudkey=0, props=0;
Aric Stewart6957e4a2005-06-08 19:16:45 +00003392 static const WCHAR szProductLanguage[] =
3393 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
Aric Stewart6957e4a2005-06-08 19:16:45 +00003394 static const WCHAR szARPProductIcon[] =
3395 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
Aric Stewartc28bb542005-06-09 15:49:11 +00003396 static const WCHAR szProductVersion[] =
3397 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
Aric Stewart6957e4a2005-06-08 19:16:45 +00003398 DWORD langid;
Aric Stewart6269f002005-01-17 13:40:39 +00003399 LPWSTR buffer;
3400 DWORD size;
Aric Stewart68b07492005-01-25 11:05:37 +00003401 MSIHANDLE hDb, hSumInfo;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003402
James Hawkinsa2df31a2007-07-02 20:21:26 -07003403 /* FIXME: also need to publish if the product is in advertise mode */
3404 if (!msi_check_publish(package))
3405 return ERROR_SUCCESS;
3406
Aric Stewart916ef942005-06-22 18:42:19 +00003407 /* write out icon files */
3408
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003409 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewart916ef942005-06-22 18:42:19 +00003410 if (rc == ERROR_SUCCESS)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003411 {
Aric Stewart916ef942005-06-22 18:42:19 +00003412 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003413 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003414 }
3415
Francois Gougetda8b3dd2005-01-26 21:09:04 +00003416 /* ok there is a lot more done here but i need to figure out what */
Aric Stewart916ef942005-06-22 18:42:19 +00003417
Aric Stewartadaef112005-07-07 20:27:06 +00003418 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003419 if (rc != ERROR_SUCCESS)
3420 goto end;
3421
Aric Stewartadaef112005-07-07 20:27:06 +00003422 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003423 if (rc != ERROR_SUCCESS)
3424 goto end;
3425
James Hawkinsc18b7752007-06-26 19:22:46 -07003426 rc = MSIREG_OpenUserDataProductKey(package->ProductCode,&hudkey,TRUE);
3427 if (rc != ERROR_SUCCESS)
3428 goto end;
3429
James Hawkins0e44e092007-07-02 20:21:58 -07003430 rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode,&props,TRUE);
James Hawkinsc18b7752007-06-26 19:22:46 -07003431 if (rc != ERROR_SUCCESS)
3432 goto end;
3433
Mike McCormack062ad502005-09-15 15:04:08 +00003434 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
Mike McCormack4db02cd2005-09-15 14:58:38 +00003435 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00003436 msi_free(buffer);
Aric Stewart6957e4a2005-06-08 19:16:45 +00003437
Mike McCormack74f0de92005-09-29 10:32:39 +00003438 langid = msi_get_property_int( package, szProductLanguage, 0 );
Mike McCormack4db02cd2005-09-15 14:58:38 +00003439 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003440
Mike McCormack062ad502005-09-15 15:04:08 +00003441 buffer = msi_dup_property( package, szARPProductIcon );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003442 if (buffer)
3443 {
Mike McCormack75658d72005-09-22 10:33:57 +00003444 LPWSTR path = build_icon_path(package,buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003445 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
Mike McCormack75658d72005-09-22 10:33:57 +00003446 msi_free( path );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003447 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003448 msi_free(buffer);
Aric Stewartc28bb542005-06-09 15:49:11 +00003449
Mike McCormack062ad502005-09-15 15:04:08 +00003450 buffer = msi_dup_property( package, szProductVersion );
Aric Stewartc28bb542005-06-09 15:49:11 +00003451 if (buffer)
3452 {
Mike McCormack230af9d2006-07-14 15:19:08 +09003453 DWORD verdword = msi_version_str_to_dword(buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003454 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
Aric Stewartc28bb542005-06-09 15:49:11 +00003455 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003456 msi_free(buffer);
Aric Stewart6957e4a2005-06-08 19:16:45 +00003457
Mike McCormackb7270b82005-12-31 13:18:11 +01003458 /* FIXME: Need to write more keys to the user registry */
Aric Stewart68b07492005-01-25 11:05:37 +00003459
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003460 hDb= alloc_msihandle( &package->db->hdr );
Dan Kegel337e1e22006-08-28 09:44:35 -07003461 if (!hDb) {
3462 rc = ERROR_NOT_ENOUGH_MEMORY;
3463 goto end;
3464 }
Aric Stewart68b07492005-01-25 11:05:37 +00003465 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003466 MsiCloseHandle(hDb);
Aric Stewart68b07492005-01-25 11:05:37 +00003467 if (rc == ERROR_SUCCESS)
3468 {
3469 WCHAR guidbuffer[0x200];
3470 size = 0x200;
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003471 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
Aric Stewart68b07492005-01-25 11:05:37 +00003472 guidbuffer, &size);
3473 if (rc == ERROR_SUCCESS)
3474 {
3475 WCHAR squashed[GUID_SIZE];
3476 /* for now we only care about the first guid */
3477 LPWSTR ptr = strchrW(guidbuffer,';');
3478 if (ptr) *ptr = 0;
3479 squash_guid(guidbuffer,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003480 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
Aric Stewart68b07492005-01-25 11:05:37 +00003481 }
3482 else
3483 {
Francois Gouget0edbaf72005-11-10 12:14:56 +00003484 ERR("Unable to query Revision_Number...\n");
Aric Stewart68b07492005-01-25 11:05:37 +00003485 rc = ERROR_SUCCESS;
3486 }
3487 MsiCloseHandle(hSumInfo);
3488 }
3489 else
3490 {
3491 ERR("Unable to open Summary Information\n");
3492 rc = ERROR_SUCCESS;
3493 }
Aric Stewart2cae30b2005-01-19 19:07:40 +00003494
James Hawkins5e46fc92007-07-02 20:20:20 -07003495 /* publish the SourceList info */
3496 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3497 {
3498 MsiSourceListSetInfoW(package->ProductCode, NULL,
3499 info->context, info->options,
3500 info->property, info->value);
3501 }
3502
3503 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3504 {
3505 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3506 disk->context, disk->options,
3507 disk->disk_id, disk->volume_label, disk->disk_prompt);
3508 }
3509
Aric Stewart6269f002005-01-17 13:40:39 +00003510end:
Aric Stewart6269f002005-01-17 13:40:39 +00003511 RegCloseKey(hkey);
Aric Stewart6269f002005-01-17 13:40:39 +00003512 RegCloseKey(hukey);
James Hawkinsc18b7752007-06-26 19:22:46 -07003513 RegCloseKey(hudkey);
3514 RegCloseKey(props);
Aric Stewart6269f002005-01-17 13:40:39 +00003515
Aric Stewart2cf222f2004-07-06 19:00:23 +00003516 return rc;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003517}
3518
Aric Stewartaded32f2005-06-23 09:46:31 +00003519static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3520{
3521 MSIPACKAGE *package = (MSIPACKAGE*)param;
3522 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3523 LPWSTR deformated_section, deformated_key, deformated_value;
3524 LPWSTR folder, fullname = NULL;
3525 MSIRECORD * uirow;
Mike McCormack38d67a42005-08-22 09:15:23 +00003526 INT action;
3527 MSICOMPONENT *comp;
Aric Stewartaded32f2005-06-23 09:46:31 +00003528 static const WCHAR szWindowsFolder[] =
3529 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3530
3531 component = MSI_RecordGetString(row, 8);
Mike McCormack38d67a42005-08-22 09:15:23 +00003532 comp = get_loaded_component(package,component);
Aric Stewartaded32f2005-06-23 09:46:31 +00003533
Mike McCormackd693f462005-10-29 11:36:48 +00003534 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewartaded32f2005-06-23 09:46:31 +00003535 {
3536 TRACE("Skipping ini file due to disabled component %s\n",
3537 debugstr_w(component));
3538
Mike McCormack38d67a42005-08-22 09:15:23 +00003539 comp->Action = comp->Installed;
Aric Stewartaded32f2005-06-23 09:46:31 +00003540
3541 return ERROR_SUCCESS;
3542 }
3543
Mike McCormack38d67a42005-08-22 09:15:23 +00003544 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewartaded32f2005-06-23 09:46:31 +00003545
3546 identifier = MSI_RecordGetString(row,1);
3547 filename = MSI_RecordGetString(row,2);
3548 dirproperty = MSI_RecordGetString(row,3);
3549 section = MSI_RecordGetString(row,4);
3550 key = MSI_RecordGetString(row,5);
3551 value = MSI_RecordGetString(row,6);
3552 action = MSI_RecordGetInteger(row,7);
3553
3554 deformat_string(package,section,&deformated_section);
3555 deformat_string(package,key,&deformated_key);
3556 deformat_string(package,value,&deformated_value);
3557
3558 if (dirproperty)
3559 {
James Hawkins8cedb212007-03-29 02:38:57 -05003560 folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
Aric Stewartaded32f2005-06-23 09:46:31 +00003561 if (!folder)
Mike McCormack062ad502005-09-15 15:04:08 +00003562 folder = msi_dup_property( package, dirproperty );
Aric Stewartaded32f2005-06-23 09:46:31 +00003563 }
3564 else
Mike McCormack062ad502005-09-15 15:04:08 +00003565 folder = msi_dup_property( package, szWindowsFolder );
Aric Stewartaded32f2005-06-23 09:46:31 +00003566
3567 if (!folder)
3568 {
3569 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3570 goto cleanup;
3571 }
3572
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003573 fullname = build_directory_name(2, folder, filename);
Aric Stewartaded32f2005-06-23 09:46:31 +00003574
3575 if (action == 0)
3576 {
3577 TRACE("Adding value %s to section %s in %s\n",
3578 debugstr_w(deformated_key), debugstr_w(deformated_section),
3579 debugstr_w(fullname));
3580 WritePrivateProfileStringW(deformated_section, deformated_key,
3581 deformated_value, fullname);
3582 }
3583 else if (action == 1)
3584 {
3585 WCHAR returned[10];
3586 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3587 returned, 10, fullname);
3588 if (returned[0] == 0)
3589 {
3590 TRACE("Adding value %s to section %s in %s\n",
3591 debugstr_w(deformated_key), debugstr_w(deformated_section),
3592 debugstr_w(fullname));
3593
3594 WritePrivateProfileStringW(deformated_section, deformated_key,
3595 deformated_value, fullname);
3596 }
3597 }
3598 else if (action == 3)
3599 FIXME("Append to existing section not yet implemented\n");
3600
3601 uirow = MSI_CreateRecord(4);
3602 MSI_RecordSetStringW(uirow,1,identifier);
3603 MSI_RecordSetStringW(uirow,2,deformated_section);
3604 MSI_RecordSetStringW(uirow,3,deformated_key);
3605 MSI_RecordSetStringW(uirow,4,deformated_value);
3606 ui_actiondata(package,szWriteIniValues,uirow);
3607 msiobj_release( &uirow->hdr );
3608cleanup:
Mike McCormackee034ba2005-09-20 11:59:14 +00003609 msi_free(fullname);
3610 msi_free(folder);
3611 msi_free(deformated_key);
3612 msi_free(deformated_value);
3613 msi_free(deformated_section);
Aric Stewartaded32f2005-06-23 09:46:31 +00003614 return ERROR_SUCCESS;
3615}
3616
Aric Stewart516a9c72005-01-14 15:59:26 +00003617static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3618{
3619 UINT rc;
3620 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003621 static const WCHAR ExecSeqQuery[] =
3622 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003623 '`','I','n','i','F','i','l','e','`',0};
Aric Stewart516a9c72005-01-14 15:59:26 +00003624
3625 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3626 if (rc != ERROR_SUCCESS)
3627 {
3628 TRACE("no IniFile table\n");
3629 return ERROR_SUCCESS;
3630 }
3631
Aric Stewartaded32f2005-06-23 09:46:31 +00003632 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
Aric Stewart516a9c72005-01-14 15:59:26 +00003633 msiobj_release(&view->hdr);
3634 return rc;
3635}
3636
Aric Stewart854bfc42005-06-24 11:33:02 +00003637static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
Aric Stewart6269f002005-01-17 13:40:39 +00003638{
Aric Stewart854bfc42005-06-24 11:33:02 +00003639 MSIPACKAGE *package = (MSIPACKAGE*)param;
3640 LPCWSTR filename;
3641 LPWSTR FullName;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003642 MSIFILE *file;
Aric Stewart854bfc42005-06-24 11:33:02 +00003643 DWORD len;
Aric Stewart8e233e92005-03-01 11:45:19 +00003644 static const WCHAR ExeStr[] =
Aric Stewartc5a14432005-05-18 17:46:12 +00003645 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3646 static const WCHAR close[] = {'\"',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00003647 STARTUPINFOW si;
3648 PROCESS_INFORMATION info;
3649 BOOL brc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003650 MSIRECORD *uirow;
3651 LPWSTR uipath, p;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003652
3653 memset(&si,0,sizeof(STARTUPINFOW));
3654
Aric Stewart854bfc42005-06-24 11:33:02 +00003655 filename = MSI_RecordGetString(row,1);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003656 file = get_loaded_file( package, filename );
Aric Stewart854bfc42005-06-24 11:33:02 +00003657
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003658 if (!file)
Aric Stewart854bfc42005-06-24 11:33:02 +00003659 {
3660 ERR("Unable to find file id %s\n",debugstr_w(filename));
3661 return ERROR_SUCCESS;
3662 }
3663
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003664 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
Aric Stewart854bfc42005-06-24 11:33:02 +00003665
Mike McCormackee034ba2005-09-20 11:59:14 +00003666 FullName = msi_alloc(len*sizeof(WCHAR));
Aric Stewart854bfc42005-06-24 11:33:02 +00003667 strcpyW(FullName,ExeStr);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003668 strcatW( FullName, file->TargetPath );
Aric Stewart854bfc42005-06-24 11:33:02 +00003669 strcatW(FullName,close);
3670
3671 TRACE("Registering %s\n",debugstr_w(FullName));
3672 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3673 &si, &info);
3674
3675 if (brc)
3676 msi_dialog_check_messages(info.hProcess);
3677
Mike McCormackee034ba2005-09-20 11:59:14 +00003678 msi_free(FullName);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003679
3680 /* the UI chunk */
3681 uirow = MSI_CreateRecord( 2 );
3682 uipath = strdupW( file->TargetPath );
3683 p = strrchrW(uipath,'\\');
3684 if (p)
Rob Shearman220f93d2007-04-24 12:33:56 +01003685 p[0]=0;
3686 MSI_RecordSetStringW( uirow, 1, &p[1] );
Robert Shearmand2e48e02006-01-23 17:29:50 +01003687 MSI_RecordSetStringW( uirow, 2, uipath);
3688 ui_actiondata( package, szSelfRegModules, uirow);
3689 msiobj_release( &uirow->hdr );
3690 msi_free( uipath );
3691 /* FIXME: call ui_progress? */
3692
Aric Stewart854bfc42005-06-24 11:33:02 +00003693 return ERROR_SUCCESS;
3694}
3695
3696static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3697{
3698 UINT rc;
3699 MSIQUERY * view;
3700 static const WCHAR ExecSeqQuery[] =
3701 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3702 '`','S','e','l','f','R','e','g','`',0};
3703
Aric Stewart6269f002005-01-17 13:40:39 +00003704 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3705 if (rc != ERROR_SUCCESS)
3706 {
3707 TRACE("no SelfReg table\n");
3708 return ERROR_SUCCESS;
3709 }
3710
Aric Stewart854bfc42005-06-24 11:33:02 +00003711 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
Aric Stewart6269f002005-01-17 13:40:39 +00003712 msiobj_release(&view->hdr);
Aric Stewart854bfc42005-06-24 11:33:02 +00003713
3714 return ERROR_SUCCESS;
Aric Stewart6269f002005-01-17 13:40:39 +00003715}
3716
3717static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3718{
Mike McCormack1da28582005-08-22 14:09:17 +00003719 MSIFEATURE *feature;
Aric Stewart6269f002005-01-17 13:40:39 +00003720 UINT rc;
Aric Stewart68b07492005-01-25 11:05:37 +00003721 HKEY hkey=0;
3722 HKEY hukey=0;
James Hawkins9f11a5a2007-11-01 03:13:28 -05003723 HKEY userdata=0;
James Hawkins6ac08162007-08-09 11:38:48 -07003724
3725 if (!msi_check_publish(package))
3726 return ERROR_SUCCESS;
3727
Aric Stewartadaef112005-07-07 20:27:06 +00003728 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003729 if (rc != ERROR_SUCCESS)
3730 goto end;
3731
Aric Stewartadaef112005-07-07 20:27:06 +00003732 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003733 if (rc != ERROR_SUCCESS)
3734 goto end;
3735
James Hawkins9f11a5a2007-11-01 03:13:28 -05003736 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &userdata, TRUE);
3737 if (rc != ERROR_SUCCESS)
3738 goto end;
3739
Aric Stewart6269f002005-01-17 13:40:39 +00003740 /* here the guids are base 85 encoded */
Mike McCormack1da28582005-08-22 14:09:17 +00003741 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00003742 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003743 ComponentList *cl;
Aric Stewart6269f002005-01-17 13:40:39 +00003744 LPWSTR data = NULL;
3745 GUID clsid;
Aric Stewart6269f002005-01-17 13:40:39 +00003746 INT size;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003747 BOOL absent = FALSE;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003748 MSIRECORD *uirow;
Aric Stewart6269f002005-01-17 13:40:39 +00003749
Mike McCormack1da28582005-08-22 14:09:17 +00003750 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3751 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3752 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003753 absent = TRUE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003754
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003755 size = 1;
Mike McCormack1da28582005-08-22 14:09:17 +00003756 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003757 {
3758 size += 21;
3759 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00003760 if (feature->Feature_Parent)
Mike McCormack1da28582005-08-22 14:09:17 +00003761 size += strlenW( feature->Feature_Parent )+2;
Aric Stewart6269f002005-01-17 13:40:39 +00003762
Mike McCormackee034ba2005-09-20 11:59:14 +00003763 data = msi_alloc(size * sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00003764
3765 data[0] = 0;
Mike McCormack1da28582005-08-22 14:09:17 +00003766 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00003767 {
Mike McCormack38d67a42005-08-22 09:15:23 +00003768 MSICOMPONENT* component = cl->component;
Aric Stewart6269f002005-01-17 13:40:39 +00003769 WCHAR buf[21];
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003770
Mike McCormack3a940112006-04-19 02:29:03 +09003771 buf[0] = 0;
Mike McCormackefcc1ec2005-09-12 12:07:15 +00003772 if (component->ComponentId)
Aric Stewartc5a14432005-05-18 17:46:12 +00003773 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003774 TRACE("From %s\n",debugstr_w(component->ComponentId));
3775 CLSIDFromString(component->ComponentId, &clsid);
Aric Stewartc5a14432005-05-18 17:46:12 +00003776 encode_base85_guid(&clsid,buf);
3777 TRACE("to %s\n",debugstr_w(buf));
3778 strcatW(data,buf);
3779 }
Aric Stewart6269f002005-01-17 13:40:39 +00003780 }
James Hawkins9f11a5a2007-11-01 03:13:28 -05003781
Mike McCormack79ca56c2005-09-13 10:37:37 +00003782 if (feature->Feature_Parent)
Aric Stewart6269f002005-01-17 13:40:39 +00003783 {
3784 static const WCHAR sep[] = {'\2',0};
3785 strcatW(data,sep);
Mike McCormack1da28582005-08-22 14:09:17 +00003786 strcatW(data,feature->Feature_Parent);
Aric Stewart6269f002005-01-17 13:40:39 +00003787 }
3788
Mike McCormack4db02cd2005-09-15 14:58:38 +00003789 msi_reg_set_val_str( hkey, feature->Feature, data );
James Hawkins9f11a5a2007-11-01 03:13:28 -05003790 msi_reg_set_val_str( userdata, feature->Feature, data );
Mike McCormackee034ba2005-09-20 11:59:14 +00003791 msi_free(data);
Aric Stewart6269f002005-01-17 13:40:39 +00003792
Mike McCormack79ca56c2005-09-13 10:37:37 +00003793 size = 0;
3794 if (feature->Feature_Parent)
3795 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003796 if (!absent)
3797 {
Mike McCormack1da28582005-08-22 14:09:17 +00003798 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3799 (LPBYTE)feature->Feature_Parent,size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003800 }
3801 else
3802 {
Mike McCormack79ca56c2005-09-13 10:37:37 +00003803 size += 2*sizeof(WCHAR);
Mike McCormackee034ba2005-09-20 11:59:14 +00003804 data = msi_alloc(size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003805 data[0] = 0x6;
Mike McCormack79ca56c2005-09-13 10:37:37 +00003806 data[1] = 0;
3807 if (feature->Feature_Parent)
3808 strcpyW( &data[1], feature->Feature_Parent );
Mike McCormack1da28582005-08-22 14:09:17 +00003809 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
Mike McCormack16466af2005-07-06 10:33:30 +00003810 (LPBYTE)data,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00003811 msi_free(data);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003812 }
Robert Shearmand2e48e02006-01-23 17:29:50 +01003813
3814 /* the UI chunk */
3815 uirow = MSI_CreateRecord( 1 );
3816 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3817 ui_actiondata( package, szPublishFeatures, uirow);
3818 msiobj_release( &uirow->hdr );
3819 /* FIXME: call ui_progress? */
Aric Stewart6269f002005-01-17 13:40:39 +00003820 }
3821
Aric Stewart6269f002005-01-17 13:40:39 +00003822end:
Aric Stewart6269f002005-01-17 13:40:39 +00003823 RegCloseKey(hkey);
3824 RegCloseKey(hukey);
3825 return rc;
3826}
3827
James Hawkins6ac08162007-08-09 11:38:48 -07003828static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3829{
3830 UINT r;
3831 HKEY hkey;
3832
3833 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3834
3835 r = MSIREG_OpenUserFeaturesKey(package->ProductCode, &hkey, FALSE);
3836 if (r == ERROR_SUCCESS)
3837 {
3838 RegDeleteValueW(hkey, feature->Feature);
3839 RegCloseKey(hkey);
3840 }
3841
3842 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, &hkey, FALSE);
3843 if (r == ERROR_SUCCESS)
3844 {
3845 RegDeleteValueW(hkey, feature->Feature);
3846 RegCloseKey(hkey);
3847 }
3848
3849 return ERROR_SUCCESS;
3850}
3851
James Hawkinsccdf5782007-11-01 03:14:18 -05003852static BOOL msi_check_unpublish(MSIPACKAGE *package)
3853{
3854 MSIFEATURE *feature;
3855
3856 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3857 {
3858 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3859 return FALSE;
3860 }
3861
3862 return TRUE;
3863}
3864
James Hawkins6ac08162007-08-09 11:38:48 -07003865static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3866{
3867 MSIFEATURE *feature;
3868
James Hawkinsccdf5782007-11-01 03:14:18 -05003869 if (!msi_check_unpublish(package))
James Hawkins6ac08162007-08-09 11:38:48 -07003870 return ERROR_SUCCESS;
3871
3872 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3873 {
3874 msi_unpublish_feature(package, feature);
3875 }
3876
3877 return ERROR_SUCCESS;
3878}
3879
Mike McCormack5f830692006-09-08 16:20:46 +09003880static UINT msi_get_local_package_name( LPWSTR path )
Mike McCormack61f24a42005-09-30 10:32:41 +00003881{
Mike McCormack5f830692006-09-08 16:20:46 +09003882 static const WCHAR szInstaller[] = {
3883 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3884 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3885 DWORD time, len, i;
3886 HANDLE handle;
Mike McCormack61f24a42005-09-30 10:32:41 +00003887
Mike McCormack5f830692006-09-08 16:20:46 +09003888 time = GetTickCount();
3889 GetWindowsDirectoryW( path, MAX_PATH );
3890 lstrcatW( path, szInstaller );
3891 CreateDirectoryW( path, NULL );
3892
3893 len = lstrlenW(path);
3894 for (i=0; i<0x10000; i++)
Mike McCormack61f24a42005-09-30 10:32:41 +00003895 {
Mike McCormack5f830692006-09-08 16:20:46 +09003896 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3897 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3898 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
Mike McCormack61f24a42005-09-30 10:32:41 +00003899 if (handle != INVALID_HANDLE_VALUE)
3900 {
3901 CloseHandle(handle);
3902 break;
3903 }
3904 if (GetLastError() != ERROR_FILE_EXISTS &&
3905 GetLastError() != ERROR_SHARING_VIOLATION)
Mike McCormack5f830692006-09-08 16:20:46 +09003906 return ERROR_FUNCTION_FAILED;
3907 }
Mike McCormack61f24a42005-09-30 10:32:41 +00003908
Mike McCormack5f830692006-09-08 16:20:46 +09003909 return ERROR_SUCCESS;
3910}
3911
3912static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3913{
Mike McCormack5f830692006-09-08 16:20:46 +09003914 WCHAR packagefile[MAX_PATH];
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05003915 HKEY props;
Mike McCormack5f830692006-09-08 16:20:46 +09003916 UINT r;
3917
3918 r = msi_get_local_package_name( packagefile );
3919 if (r != ERROR_SUCCESS)
3920 return r;
Mike McCormack61f24a42005-09-30 10:32:41 +00003921
3922 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3923
James Hawkinsc37849a2008-01-05 13:50:59 -07003924 r = CopyFileW( package->db->path, packagefile, FALSE);
Mike McCormack61f24a42005-09-30 10:32:41 +00003925
3926 if (!r)
3927 {
Mike McCormackf1d46462006-10-05 13:41:22 +09003928 ERR("Unable to copy package (%s -> %s) (error %d)\n",
James Hawkinsc37849a2008-01-05 13:50:59 -07003929 debugstr_w(package->db->path), debugstr_w(packagefile), GetLastError());
Mike McCormack61f24a42005-09-30 10:32:41 +00003930 return ERROR_FUNCTION_FAILED;
3931 }
3932
Mike McCormack61f24a42005-09-30 10:32:41 +00003933 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05003934
3935 r = MSIREG_OpenInstallPropertiesKey(package->ProductCode, &props, TRUE);
3936 if (r != ERROR_SUCCESS)
3937 return r;
3938
3939 msi_reg_set_val_str(props, INSTALLPROPERTY_LOCALPACKAGEW, packagefile);
3940 RegCloseKey(props);
Mike McCormack61f24a42005-09-30 10:32:41 +00003941 return ERROR_SUCCESS;
3942}
3943
Mike McCormackba293ee2005-10-27 12:08:16 +00003944static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3945{
3946 LPWSTR prop, val, key;
3947 static const LPCSTR propval[] = {
3948 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3949 "ARPCONTACT", "Contact",
3950 "ARPCOMMENTS", "Comments",
3951 "ProductName", "DisplayName",
3952 "ProductVersion", "DisplayVersion",
3953 "ARPHELPLINK", "HelpLink",
3954 "ARPHELPTELEPHONE", "HelpTelephone",
3955 "ARPINSTALLLOCATION", "InstallLocation",
3956 "SourceDir", "InstallSource",
3957 "Manufacturer", "Publisher",
3958 "ARPREADME", "Readme",
3959 "ARPSIZE", "Size",
3960 "ARPURLINFOABOUT", "URLInfoAbout",
3961 "ARPURLUPDATEINFO", "URLUpdateInfo",
3962 NULL,
3963 };
3964 const LPCSTR *p = propval;
3965
3966 while( *p )
3967 {
3968 prop = strdupAtoW( *p++ );
3969 key = strdupAtoW( *p++ );
3970 val = msi_dup_property( package, prop );
3971 msi_reg_set_val_str( hkey, key, val );
3972 msi_free(val);
3973 msi_free(key);
3974 msi_free(prop);
3975 }
3976 return ERROR_SUCCESS;
3977}
3978
Aric Stewart2cae30b2005-01-19 19:07:40 +00003979static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3980{
Aric Stewart68b07492005-01-25 11:05:37 +00003981 HKEY hkey=0;
James Hawkins0e44e092007-07-02 20:21:58 -07003982 HKEY hudkey=0, props=0;
Aric Stewarte9db87b2005-06-17 21:25:41 +00003983 LPWSTR buffer = NULL;
Mike McCormackba293ee2005-10-27 12:08:16 +00003984 UINT rc;
Mike McCormack74f0de92005-09-29 10:32:39 +00003985 DWORD size, langid;
Mike McCormack4db02cd2005-09-15 14:58:38 +00003986 static const WCHAR szWindowsInstaller[] =
Mike McCormackba293ee2005-10-27 12:08:16 +00003987 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
Aric Stewart36a01502005-06-08 19:07:52 +00003988 static const WCHAR szUpgradeCode[] =
3989 {'U','p','g','r','a','d','e','C','o','d','e',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003990 static const WCHAR modpath_fmt[] =
Mike McCormackba293ee2005-10-27 12:08:16 +00003991 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3992 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003993 static const WCHAR szModifyPath[] =
3994 {'M','o','d','i','f','y','P','a','t','h',0};
3995 static const WCHAR szUninstallString[] =
3996 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3997 static const WCHAR szEstimatedSize[] =
3998 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003999 static const WCHAR szProductLanguage[] =
4000 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4001 static const WCHAR szProductVersion[] =
4002 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',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
4017 /* dump all the info i can grab */
Mike McCormackb7270b82005-12-31 13:18:11 +01004018 /* FIXME: Flesh out more information */
Aric Stewart2cae30b2005-01-19 19:07:40 +00004019
Mike McCormackba293ee2005-10-27 12:08:16 +00004020 msi_write_uninstall_property_vals( package, hkey );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004021
Mike McCormack4db02cd2005-09-15 14:58:38 +00004022 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004023
Mike McCormack61f24a42005-09-30 10:32:41 +00004024 msi_make_package_local( package, hkey );
Aric Stewart36a01502005-06-08 19:07:52 +00004025
Aric Stewarte9db87b2005-06-17 21:25:41 +00004026 /* do ModifyPath and UninstallString */
4027 size = deformat_string(package,modpath_fmt,&buffer);
Mike McCormack16466af2005-07-06 10:33:30 +00004028 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
4029 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00004030 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00004031
Mike McCormackb7270b82005-12-31 13:18:11 +01004032 /* FIXME: Write real Estimated Size when we have it */
Mike McCormack4db02cd2005-09-15 14:58:38 +00004033 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004034
4035 GetLocalTime(&systime);
Mike McCormackba293ee2005-10-27 12:08:16 +00004036 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
4037 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004038
Mike McCormack74f0de92005-09-29 10:32:39 +00004039 langid = msi_get_property_int( package, szProductLanguage, 0 );
4040 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004041
Mike McCormack062ad502005-09-15 15:04:08 +00004042 buffer = msi_dup_property( package, szProductVersion );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004043 if (buffer)
4044 {
Mike McCormack230af9d2006-07-14 15:19:08 +09004045 DWORD verdword = msi_version_str_to_dword(buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00004046
4047 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
4048 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
4049 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
Aric Stewarte9db87b2005-06-17 21:25:41 +00004050 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004051 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00004052
Aric Stewart36a01502005-06-08 19:07:52 +00004053 /* Handle Upgrade Codes */
Mike McCormack062ad502005-09-15 15:04:08 +00004054 upgrade_code = msi_dup_property( package, szUpgradeCode );
Aric Stewart36a01502005-06-08 19:07:52 +00004055 if (upgrade_code)
4056 {
4057 HKEY hkey2;
4058 WCHAR squashed[33];
4059 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
Aric Stewartadaef112005-07-07 20:27:06 +00004060 squash_guid(package->ProductCode,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00004061 msi_reg_set_val_str( hkey2, squashed, NULL );
Aric Stewart36a01502005-06-08 19:07:52 +00004062 RegCloseKey(hkey2);
4063 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
Aric Stewartadaef112005-07-07 20:27:06 +00004064 squash_guid(package->ProductCode,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00004065 msi_reg_set_val_str( hkey2, squashed, NULL );
Aric Stewart36a01502005-06-08 19:07:52 +00004066 RegCloseKey(hkey2);
4067
Mike McCormackee034ba2005-09-20 11:59:14 +00004068 msi_free(upgrade_code);
Aric Stewart36a01502005-06-08 19:07:52 +00004069 }
Aric Stewart2cae30b2005-01-19 19:07:40 +00004070
Aric Stewart2cae30b2005-01-19 19:07:40 +00004071 RegCloseKey(hkey);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004072
James Hawkins0e44e092007-07-02 20:21:58 -07004073 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, &hudkey, TRUE);
4074 if (rc != ERROR_SUCCESS)
4075 return rc;
4076
4077 RegCloseKey(hudkey);
4078
4079 rc = MSIREG_OpenInstallPropertiesKey(package->ProductCode, &props, TRUE);
4080 if (rc != ERROR_SUCCESS)
4081 return rc;
4082
4083 msi_reg_set_val_dword( props, szWindowsInstaller, 1 );
4084 RegCloseKey(props);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004085
Aric Stewart2cae30b2005-01-19 19:07:40 +00004086 return ERROR_SUCCESS;
4087}
4088
4089static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4090{
Mike McCormacka977b2c2005-11-03 09:56:29 +00004091 return execute_script(package,INSTALL_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004092}
4093
James Hawkins624bbbe2007-07-02 20:20:54 -07004094static UINT msi_unpublish_product(MSIPACKAGE *package)
4095{
4096 LPWSTR remove = NULL;
4097 LPWSTR *features = NULL;
4098 BOOL full_uninstall = TRUE;
4099 MSIFEATURE *feature;
4100
4101 static const WCHAR szRemove[] = {'R','E','M','O','V','E',0};
4102 static const WCHAR szAll[] = {'A','L','L',0};
4103
4104 remove = msi_dup_property(package, szRemove);
4105 if (!remove)
4106 return ERROR_SUCCESS;
4107
4108 features = msi_split_string(remove, ',');
4109 if (!features)
4110 {
4111 msi_free(remove);
4112 ERR("REMOVE feature list is empty!\n");
4113 return ERROR_FUNCTION_FAILED;
4114 }
4115
4116 if (!lstrcmpW(features[0], szAll))
4117 full_uninstall = TRUE;
4118 else
4119 {
4120 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4121 {
4122 if (feature->Action != INSTALLSTATE_ABSENT)
4123 full_uninstall = FALSE;
4124 }
4125 }
4126
4127 if (!full_uninstall)
4128 goto done;
4129
4130 MSIREG_DeleteProductKey(package->ProductCode);
4131 MSIREG_DeleteUserProductKey(package->ProductCode);
4132 MSIREG_DeleteUserDataProductKey(package->ProductCode);
James Hawkins6ac08162007-08-09 11:38:48 -07004133 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
James Hawkinsf6b27672007-11-13 00:47:21 -06004134 MSIREG_DeleteUninstallKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004135
4136done:
4137 msi_free(remove);
4138 msi_free(features);
4139 return ERROR_SUCCESS;
4140}
4141
Aric Stewart2cae30b2005-01-19 19:07:40 +00004142static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4143{
Aric Stewart9cd707d2005-05-27 19:24:22 +00004144 UINT rc;
4145
James Hawkins624bbbe2007-07-02 20:20:54 -07004146 rc = msi_unpublish_product(package);
4147 if (rc != ERROR_SUCCESS)
4148 return rc;
4149
Francois Gouget1ccf9442006-11-12 19:51:37 +01004150 /* turn off scheduling */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004151 package->script->CurrentlyScripting= FALSE;
4152
Aric Stewart54c67dd2005-01-25 20:17:09 +00004153 /* first do the same as an InstallExecute */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004154 rc = ACTION_InstallExecute(package);
4155 if (rc != ERROR_SUCCESS)
4156 return rc;
Aric Stewart54c67dd2005-01-25 20:17:09 +00004157
4158 /* then handle Commit Actions */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004159 rc = execute_script(package,COMMIT_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004160
Aric Stewart9cd707d2005-05-27 19:24:22 +00004161 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004162}
4163
James Hawkinsc2e91582007-05-29 12:03:05 -07004164UINT ACTION_ForceReboot(MSIPACKAGE *package)
Aric Stewart2cae30b2005-01-19 19:07:40 +00004165{
4166 static const WCHAR RunOnce[] = {
4167 'S','o','f','t','w','a','r','e','\\',
4168 'M','i','c','r','o','s','o','f','t','\\',
4169 'W','i','n','d','o','w','s','\\',
4170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004171 'R','u','n','O','n','c','e',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004172 static const WCHAR InstallRunOnce[] = {
4173 'S','o','f','t','w','a','r','e','\\',
4174 'M','i','c','r','o','s','o','f','t','\\',
4175 'W','i','n','d','o','w','s','\\',
4176 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4177 'I','n','s','t','a','l','l','e','r','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004178 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004179
4180 static const WCHAR msiexec_fmt[] = {
Juan Lang014ad3b2005-03-01 10:41:52 +00004181 '%','s',
Aric Stewart2cae30b2005-01-19 19:07:40 +00004182 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4183 '\"','%','s','\"',0};
4184 static const WCHAR install_fmt[] = {
4185 '/','I',' ','\"','%','s','\"',' ',
4186 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4187 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
Juan Lang014ad3b2005-03-01 10:41:52 +00004188 WCHAR buffer[256], sysdir[MAX_PATH];
Aric Stewartadaef112005-07-07 20:27:06 +00004189 HKEY hkey;
Mike McCormack4db02cd2005-09-15 14:58:38 +00004190 WCHAR squished_pc[100];
Aric Stewart2cae30b2005-01-19 19:07:40 +00004191
Aric Stewartadaef112005-07-07 20:27:06 +00004192 squash_guid(package->ProductCode,squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004193
Juan Lang014ad3b2005-03-01 10:41:52 +00004194 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
Aric Stewart2cae30b2005-01-19 19:07:40 +00004195 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
Juan Lang014ad3b2005-03-01 10:41:52 +00004196 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4197 squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004198
Mike McCormack4db02cd2005-09-15 14:58:38 +00004199 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004200 RegCloseKey(hkey);
4201
4202 TRACE("Reboot command %s\n",debugstr_w(buffer));
4203
4204 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
Aric Stewartadaef112005-07-07 20:27:06 +00004205 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004206
Mike McCormack4db02cd2005-09-15 14:58:38 +00004207 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004208 RegCloseKey(hkey);
4209
Aric Stewart68b07492005-01-25 11:05:37 +00004210 return ERROR_INSTALL_SUSPEND;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004211}
4212
James Hawkins563a50a2006-10-09 00:05:04 -07004213static UINT ACTION_ResolveSource(MSIPACKAGE* package)
Aric Stewart90c57392005-01-31 16:23:12 +00004214{
Mike McCormackb9211182006-11-20 16:27:36 +09004215 DWORD attrib;
Aric Stewart94d68182005-08-15 20:50:06 +00004216 UINT rc;
Mike McCormackfc564232006-11-20 16:17:03 +09004217
Aric Stewart90c57392005-01-31 16:23:12 +00004218 /*
Mike McCormackfc564232006-11-20 16:17:03 +09004219 * We are currently doing what should be done here in the top level Install
4220 * however for Administrative and uninstalls this step will be needed
Aric Stewart90c57392005-01-31 16:23:12 +00004221 */
Aric Stewart94d68182005-08-15 20:50:06 +00004222 if (!package->PackagePath)
4223 return ERROR_SUCCESS;
4224
James Hawkinsc777d302008-01-05 13:45:13 -07004225 msi_set_sourcedir_props(package, TRUE);
James Hawkinsc5075432006-10-10 13:39:50 -07004226
James Hawkinse28cedf2008-01-05 13:48:32 -07004227 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004228 if (attrib == INVALID_FILE_ATTRIBUTES)
4229 {
4230 LPWSTR prompt;
4231 LPWSTR msg;
4232 DWORD size = 0;
4233
4234 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
4235 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
4236 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4237 if (rc == ERROR_MORE_DATA)
4238 {
Mike McCormackee034ba2005-09-20 11:59:14 +00004239 prompt = msi_alloc(size * sizeof(WCHAR));
Aric Stewart94d68182005-08-15 20:50:06 +00004240 MsiSourceListGetInfoW(package->ProductCode, NULL,
4241 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
4242 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4243 }
4244 else
James Hawkinse28cedf2008-01-05 13:48:32 -07004245 prompt = strdupW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004246
4247 msg = generate_error_string(package,1302,1,prompt);
4248 while(attrib == INVALID_FILE_ATTRIBUTES)
4249 {
4250 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4251 if (rc == IDCANCEL)
4252 {
4253 rc = ERROR_INSTALL_USEREXIT;
4254 break;
4255 }
James Hawkinse28cedf2008-01-05 13:48:32 -07004256 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004257 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004258 msi_free(prompt);
Aric Stewart94d68182005-08-15 20:50:06 +00004259 rc = ERROR_SUCCESS;
4260 }
4261 else
4262 return ERROR_SUCCESS;
4263
4264 return rc;
Aric Stewart90c57392005-01-31 16:23:12 +00004265}
4266
Aric Stewartc7e88e02005-02-10 17:09:44 +00004267static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4268{
Aric Stewartc7e88e02005-02-10 17:09:44 +00004269 HKEY hkey=0;
4270 LPWSTR buffer;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004271 LPWSTR productid;
4272 UINT rc,i;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004273
4274 static const WCHAR szPropKeys[][80] =
4275 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004276 {'P','r','o','d','u','c','t','I','D',0},
4277 {'U','S','E','R','N','A','M','E',0},
4278 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4279 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004280 };
4281
4282 static const WCHAR szRegKeys[][80] =
4283 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004284 {'P','r','o','d','u','c','t','I','D',0},
4285 {'R','e','g','O','w','n','e','r',0},
4286 {'R','e','g','C','o','m','p','a','n','y',0},
4287 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004288 };
4289
Mike McCormack062ad502005-09-15 15:04:08 +00004290 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004291 if (!productid)
4292 return ERROR_SUCCESS;
4293
Aric Stewartadaef112005-07-07 20:27:06 +00004294 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004295 if (rc != ERROR_SUCCESS)
4296 goto end;
4297
Mike McCormack67189f92005-09-16 18:45:19 +00004298 for( i = 0; szPropKeys[i][0]; i++ )
Aric Stewartc7e88e02005-02-10 17:09:44 +00004299 {
Mike McCormack062ad502005-09-15 15:04:08 +00004300 buffer = msi_dup_property( package, szPropKeys[i] );
Mike McCormack4db02cd2005-09-15 14:58:38 +00004301 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00004302 msi_free( buffer );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004303 }
4304
4305end:
Mike McCormackee034ba2005-09-20 11:59:14 +00004306 msi_free(productid);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004307 RegCloseKey(hkey);
4308
Robert Shearmand2e48e02006-01-23 17:29:50 +01004309 /* FIXME: call ui_actiondata */
4310
Aric Stewartc7e88e02005-02-10 17:09:44 +00004311 return ERROR_SUCCESS;
4312}
4313
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004314
4315static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
4316{
4317 UINT rc;
Aric Stewart25f1e752005-06-24 12:14:52 +00004318
Aric Stewartc9802932005-06-30 20:45:43 +00004319 package->script->InWhatSequence |= SEQUENCE_EXEC;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004320 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004321 return rc;
4322}
4323
Aric Stewart0af24872005-02-25 14:00:09 +00004324
Aric Stewart072c5e52005-04-20 12:50:05 +00004325static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4326{
4327 MSIPACKAGE *package = (MSIPACKAGE*)param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00004328 LPCWSTR compgroupid=NULL;
4329 LPCWSTR feature=NULL;
4330 LPCWSTR text = NULL;
4331 LPCWSTR qualifier = NULL;
4332 LPCWSTR component = NULL;
Aric Stewart6f43c182005-05-26 12:24:28 +00004333 LPWSTR advertise = NULL;
4334 LPWSTR output = NULL;
Aric Stewart072c5e52005-04-20 12:50:05 +00004335 HKEY hkey;
4336 UINT rc = ERROR_SUCCESS;
Mike McCormack38d67a42005-08-22 09:15:23 +00004337 MSICOMPONENT *comp;
Aric Stewart072c5e52005-04-20 12:50:05 +00004338 DWORD sz = 0;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004339 MSIRECORD *uirow;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004340
Aric Stewart09b0aba2005-06-09 20:30:59 +00004341 component = MSI_RecordGetString(rec,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00004342 comp = get_loaded_component(package,component);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004343
Mike McCormackd693f462005-10-29 11:36:48 +00004344 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4345 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4346 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004347 {
4348 TRACE("Skipping: Component %s not scheduled for install\n",
4349 debugstr_w(component));
Aric Stewart6f43c182005-05-26 12:24:28 +00004350
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004351 return ERROR_SUCCESS;
4352 }
Aric Stewart072c5e52005-04-20 12:50:05 +00004353
Aric Stewart09b0aba2005-06-09 20:30:59 +00004354 compgroupid = MSI_RecordGetString(rec,1);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004355 qualifier = MSI_RecordGetString(rec,2);
Aric Stewart072c5e52005-04-20 12:50:05 +00004356
4357 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4358 if (rc != ERROR_SUCCESS)
4359 goto end;
4360
Aric Stewart09b0aba2005-06-09 20:30:59 +00004361 text = MSI_RecordGetString(rec,4);
Aric Stewart09b0aba2005-06-09 20:30:59 +00004362 feature = MSI_RecordGetString(rec,5);
Aric Stewart072c5e52005-04-20 12:50:05 +00004363
Mike McCormack38d67a42005-08-22 09:15:23 +00004364 advertise = create_component_advertise_string(package, comp, feature);
Aric Stewart072c5e52005-04-20 12:50:05 +00004365
Aric Stewart6f43c182005-05-26 12:24:28 +00004366 sz = strlenW(advertise);
4367
Aric Stewart072c5e52005-04-20 12:50:05 +00004368 if (text)
4369 sz += lstrlenW(text);
Aric Stewart072c5e52005-04-20 12:50:05 +00004370
4371 sz+=3;
4372 sz *= sizeof(WCHAR);
4373
Mike McCormack3a940112006-04-19 02:29:03 +09004374 output = msi_alloc_zero(sz);
Aric Stewart6f43c182005-05-26 12:24:28 +00004375 strcpyW(output,advertise);
Mike McCormack470f23d2005-09-22 10:56:26 +00004376 msi_free(advertise);
Aric Stewart072c5e52005-04-20 12:50:05 +00004377
4378 if (text)
4379 strcatW(output,text);
4380
Mike McCormack4db02cd2005-09-15 14:58:38 +00004381 msi_reg_set_val_multi_str( hkey, qualifier, output );
Aric Stewart072c5e52005-04-20 12:50:05 +00004382
4383end:
4384 RegCloseKey(hkey);
Mike McCormackee034ba2005-09-20 11:59:14 +00004385 msi_free(output);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004386
4387 /* the UI chunk */
4388 uirow = MSI_CreateRecord( 2 );
4389 MSI_RecordSetStringW( uirow, 1, compgroupid );
4390 MSI_RecordSetStringW( uirow, 2, qualifier);
4391 ui_actiondata( package, szPublishComponents, uirow);
4392 msiobj_release( &uirow->hdr );
4393 /* FIXME: call ui_progress? */
4394
Aric Stewart072c5e52005-04-20 12:50:05 +00004395 return rc;
4396}
4397
4398/*
4399 * At present I am ignorning the advertised components part of this and only
4400 * focusing on the qualified component sets
4401 */
4402static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4403{
4404 UINT rc;
4405 MSIQUERY * view;
4406 static const WCHAR ExecSeqQuery[] =
4407 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00004408 '`','P','u','b','l','i','s','h',
4409 'C','o','m','p','o','n','e','n','t','`',0};
Aric Stewart072c5e52005-04-20 12:50:05 +00004410
4411 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4412 if (rc != ERROR_SUCCESS)
4413 return ERROR_SUCCESS;
4414
4415 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4416 msiobj_release(&view->hdr);
4417
4418 return rc;
4419}
Mike McCormack202166c2005-09-23 10:09:18 +00004420
James Hawkins9bc12ad2006-10-19 15:49:54 -07004421static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4422{
4423 MSIPACKAGE *package = (MSIPACKAGE*)param;
4424 MSIRECORD *row;
4425 MSIFILE *file;
4426 SC_HANDLE hscm, service = NULL;
4427 LPCWSTR name, disp, comp, depends, pass;
4428 LPCWSTR load_order, serv_name, key;
4429 DWORD serv_type, start_type;
4430 DWORD err_control;
4431
4432 static const WCHAR query[] =
4433 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4434 '`','C','o','m','p','o','n','e','n','t','`',' ',
4435 'W','H','E','R','E',' ',
4436 '`','C','o','m','p','o','n','e','n','t','`',' ',
4437 '=','\'','%','s','\'',0};
4438
4439 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4440 if (!hscm)
4441 {
4442 ERR("Failed to open the SC Manager!\n");
4443 goto done;
4444 }
4445
4446 start_type = MSI_RecordGetInteger(rec, 5);
4447 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4448 goto done;
4449
4450 depends = MSI_RecordGetString(rec, 8);
4451 if (depends && *depends)
4452 FIXME("Dependency list unhandled!\n");
4453
4454 name = MSI_RecordGetString(rec, 2);
4455 disp = MSI_RecordGetString(rec, 3);
4456 serv_type = MSI_RecordGetInteger(rec, 4);
4457 err_control = MSI_RecordGetInteger(rec, 6);
4458 load_order = MSI_RecordGetString(rec, 7);
4459 serv_name = MSI_RecordGetString(rec, 9);
4460 pass = MSI_RecordGetString(rec, 10);
4461 comp = MSI_RecordGetString(rec, 12);
4462
4463 /* fetch the service path */
4464 row = MSI_QueryGetRecord(package->db, query, comp);
4465 if (!row)
4466 {
4467 ERR("Control query failed!\n");
4468 goto done;
4469 }
4470
4471 key = MSI_RecordGetString(row, 6);
James Hawkins9bc12ad2006-10-19 15:49:54 -07004472
4473 file = get_loaded_file(package, key);
James Hawkinsb6cfc402007-10-23 03:06:59 -05004474 msiobj_release(&row->hdr);
James Hawkins9bc12ad2006-10-19 15:49:54 -07004475 if (!file)
4476 {
4477 ERR("Failed to load the service file\n");
4478 goto done;
4479 }
4480
4481 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4482 start_type, err_control, file->TargetPath,
4483 load_order, NULL, NULL, serv_name, pass);
4484 if (!service)
4485 {
4486 if (GetLastError() != ERROR_SERVICE_EXISTS)
4487 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4488 }
4489
4490done:
4491 CloseServiceHandle(service);
4492 CloseServiceHandle(hscm);
4493
4494 return ERROR_SUCCESS;
4495}
4496
4497static UINT ACTION_InstallServices( MSIPACKAGE *package )
4498{
4499 UINT rc;
4500 MSIQUERY * view;
4501 static const WCHAR ExecSeqQuery[] =
4502 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4503 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4504
4505 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4506 if (rc != ERROR_SUCCESS)
4507 return ERROR_SUCCESS;
4508
4509 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4510 msiobj_release(&view->hdr);
4511
4512 return rc;
4513}
4514
James Hawkins58bb3572006-12-01 13:22:59 -08004515/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
James Hawkinscf8e9e32007-11-05 04:37:44 -05004516static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
James Hawkins58bb3572006-12-01 13:22:59 -08004517{
Lionel Debroux99ad76c2007-12-30 19:01:09 +01004518 LPCWSTR *vector, *temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08004519 LPWSTR p, q;
4520 DWORD sep_len;
4521
4522 static const WCHAR separator[] = {'[','~',']',0};
4523
4524 *numargs = 0;
4525 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4526
4527 if (!args)
4528 return NULL;
4529
4530 vector = msi_alloc(sizeof(LPWSTR));
4531 if (!vector)
4532 return NULL;
4533
4534 p = args;
4535 do
4536 {
4537 (*numargs)++;
4538 vector[*numargs - 1] = p;
4539
4540 if ((q = strstrW(p, separator)))
4541 {
4542 *q = '\0';
4543
Lionel Debroux99ad76c2007-12-30 19:01:09 +01004544 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4545 if (!temp_vector)
4546 {
4547 msi_free(vector);
James Hawkins58bb3572006-12-01 13:22:59 -08004548 return NULL;
Lionel Debroux99ad76c2007-12-30 19:01:09 +01004549 }
4550 vector = temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08004551
4552 p = q + sep_len;
4553 }
4554 } while (q);
4555
4556 return vector;
4557}
4558
James Hawkins58bb3572006-12-01 13:22:59 -08004559static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4560{
4561 MSIPACKAGE *package = (MSIPACKAGE *)param;
4562 MSICOMPONENT *comp;
4563 SC_HANDLE scm, service = NULL;
4564 LPCWSTR name, *vector = NULL;
4565 LPWSTR args;
4566 DWORD event, numargs;
4567 UINT r = ERROR_FUNCTION_FAILED;
4568
James Hawkinseec9bbb2007-11-01 03:10:47 -05004569 comp = get_loaded_component(package, MSI_RecordGetString(rec, 6));
James Hawkins58bb3572006-12-01 13:22:59 -08004570 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4571 return ERROR_SUCCESS;
4572
4573 name = MSI_RecordGetString(rec, 2);
4574 event = MSI_RecordGetInteger(rec, 3);
4575 args = strdupW(MSI_RecordGetString(rec, 4));
4576
4577 if (!(event & msidbServiceControlEventStart))
4578 return ERROR_SUCCESS;
4579
4580 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4581 if (!scm)
4582 {
4583 ERR("Failed to open the service control manager\n");
4584 goto done;
4585 }
4586
4587 service = OpenServiceW(scm, name, SERVICE_START);
4588 if (!service)
4589 {
Francois Gougetaab5e582007-01-18 11:40:15 +01004590 ERR("Failed to open service %s\n", debugstr_w(name));
James Hawkins58bb3572006-12-01 13:22:59 -08004591 goto done;
4592 }
4593
James Hawkinscf8e9e32007-11-05 04:37:44 -05004594 vector = msi_service_args_to_vector(args, &numargs);
James Hawkins58bb3572006-12-01 13:22:59 -08004595
4596 if (!StartServiceW(service, numargs, vector))
4597 {
Francois Gougetaab5e582007-01-18 11:40:15 +01004598 ERR("Failed to start service %s\n", debugstr_w(name));
James Hawkins58bb3572006-12-01 13:22:59 -08004599 goto done;
4600 }
4601
4602 r = ERROR_SUCCESS;
4603
4604done:
4605 CloseServiceHandle(service);
4606 CloseServiceHandle(scm);
4607
4608 msi_free(args);
4609 msi_free(vector);
4610 return r;
4611}
4612
4613static UINT ACTION_StartServices( MSIPACKAGE *package )
4614{
4615 UINT rc;
4616 MSIQUERY *view;
4617
4618 static const WCHAR query[] = {
4619 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4620 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4621
4622 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4623 if (rc != ERROR_SUCCESS)
4624 return ERROR_SUCCESS;
4625
4626 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4627 msiobj_release(&view->hdr);
4628
4629 return rc;
4630}
4631
James Hawkinsd3bec322006-11-27 18:20:33 -08004632static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4633{
4634 MSIFILE *file;
4635
4636 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4637 {
4638 if (!lstrcmpW(file->File, filename))
4639 return file;
4640 }
4641
4642 return NULL;
4643}
4644
4645static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4646{
4647 MSIPACKAGE *package = (MSIPACKAGE*)param;
4648 LPWSTR driver, driver_path, ptr;
4649 WCHAR outpath[MAX_PATH];
4650 MSIFILE *driver_file, *setup_file;
4651 LPCWSTR desc;
4652 DWORD len, usage;
4653 UINT r = ERROR_SUCCESS;
4654
4655 static const WCHAR driver_fmt[] = {
4656 'D','r','i','v','e','r','=','%','s',0};
4657 static const WCHAR setup_fmt[] = {
4658 'S','e','t','u','p','=','%','s',0};
4659 static const WCHAR usage_fmt[] = {
4660 'F','i','l','e','U','s','a','g','e','=','1',0};
4661
4662 desc = MSI_RecordGetString(rec, 3);
4663
4664 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4665 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4666
4667 if (!driver_file || !setup_file)
4668 {
4669 ERR("ODBC Driver entry not found!\n");
4670 return ERROR_FUNCTION_FAILED;
4671 }
4672
4673 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4674 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4675 lstrlenW(usage_fmt) + 1;
4676 driver = msi_alloc(len * sizeof(WCHAR));
4677 if (!driver)
4678 return ERROR_OUTOFMEMORY;
4679
4680 ptr = driver;
4681 lstrcpyW(ptr, desc);
4682 ptr += lstrlenW(ptr) + 1;
4683
4684 sprintfW(ptr, driver_fmt, driver_file->FileName);
4685 ptr += lstrlenW(ptr) + 1;
4686
4687 sprintfW(ptr, setup_fmt, setup_file->FileName);
4688 ptr += lstrlenW(ptr) + 1;
4689
4690 lstrcpyW(ptr, usage_fmt);
4691 ptr += lstrlenW(ptr) + 1;
4692 *ptr = '\0';
4693
4694 driver_path = strdupW(driver_file->TargetPath);
4695 ptr = strrchrW(driver_path, '\\');
4696 if (ptr) *ptr = '\0';
4697
4698 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4699 NULL, ODBC_INSTALL_COMPLETE, &usage))
4700 {
4701 ERR("Failed to install SQL driver!\n");
4702 r = ERROR_FUNCTION_FAILED;
4703 }
4704
4705 msi_free(driver);
4706 msi_free(driver_path);
4707
4708 return r;
4709}
4710
Hans Leidekker33c025b2007-04-22 11:37:51 +02004711static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
4712{
4713 MSIPACKAGE *package = (MSIPACKAGE*)param;
4714 LPWSTR translator, translator_path, ptr;
4715 WCHAR outpath[MAX_PATH];
4716 MSIFILE *translator_file, *setup_file;
4717 LPCWSTR desc;
4718 DWORD len, usage;
4719 UINT r = ERROR_SUCCESS;
4720
4721 static const WCHAR translator_fmt[] = {
4722 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
4723 static const WCHAR setup_fmt[] = {
4724 'S','e','t','u','p','=','%','s',0};
4725
4726 desc = MSI_RecordGetString(rec, 3);
4727
4728 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4729 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4730
4731 if (!translator_file || !setup_file)
4732 {
4733 ERR("ODBC Translator entry not found!\n");
4734 return ERROR_FUNCTION_FAILED;
4735 }
4736
4737 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) +
4738 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) + 1;
4739 translator = msi_alloc(len * sizeof(WCHAR));
4740 if (!translator)
4741 return ERROR_OUTOFMEMORY;
4742
4743 ptr = translator;
4744 lstrcpyW(ptr, desc);
4745 ptr += lstrlenW(ptr) + 1;
4746
4747 sprintfW(ptr, translator_fmt, translator_file->FileName);
4748 ptr += lstrlenW(ptr) + 1;
4749
4750 sprintfW(ptr, setup_fmt, setup_file->FileName);
4751 ptr += lstrlenW(ptr) + 1;
4752 *ptr = '\0';
4753
4754 translator_path = strdupW(translator_file->TargetPath);
4755 ptr = strrchrW(translator_path, '\\');
4756 if (ptr) *ptr = '\0';
4757
4758 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
4759 NULL, ODBC_INSTALL_COMPLETE, &usage))
4760 {
4761 ERR("Failed to install SQL translator!\n");
4762 r = ERROR_FUNCTION_FAILED;
4763 }
4764
4765 msi_free(translator);
4766 msi_free(translator_path);
4767
4768 return r;
4769}
4770
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02004771static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
4772{
4773 LPWSTR attrs;
4774 LPCWSTR desc, driver;
4775 WORD request = ODBC_ADD_SYS_DSN;
4776 INT registration;
4777 DWORD len;
4778 UINT r = ERROR_SUCCESS;
4779
4780 static const WCHAR attrs_fmt[] = {
4781 'D','S','N','=','%','s',0 };
4782
4783 desc = MSI_RecordGetString(rec, 3);
4784 driver = MSI_RecordGetString(rec, 4);
4785 registration = MSI_RecordGetInteger(rec, 5);
4786
4787 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
4788 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
4789
4790 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 1 + 1;
4791 attrs = msi_alloc(len * sizeof(WCHAR));
4792 if (!attrs)
4793 return ERROR_OUTOFMEMORY;
4794
4795 sprintfW(attrs, attrs_fmt, desc);
4796 attrs[len - 1] = '\0';
4797
4798 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
4799 {
4800 ERR("Failed to install SQL data source!\n");
4801 r = ERROR_FUNCTION_FAILED;
4802 }
4803
4804 msi_free(attrs);
4805
4806 return r;
4807}
4808
James Hawkinsd3bec322006-11-27 18:20:33 -08004809static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4810{
4811 UINT rc;
4812 MSIQUERY *view;
4813
Hans Leidekker33c025b2007-04-22 11:37:51 +02004814 static const WCHAR driver_query[] = {
James Hawkinsd3bec322006-11-27 18:20:33 -08004815 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4816 'O','D','B','C','D','r','i','v','e','r',0 };
4817
Hans Leidekker33c025b2007-04-22 11:37:51 +02004818 static const WCHAR translator_query[] = {
4819 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4820 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
4821
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02004822 static const WCHAR source_query[] = {
4823 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4824 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
4825
Hans Leidekker33c025b2007-04-22 11:37:51 +02004826 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
James Hawkinsd3bec322006-11-27 18:20:33 -08004827 if (rc != ERROR_SUCCESS)
4828 return ERROR_SUCCESS;
4829
4830 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4831 msiobj_release(&view->hdr);
4832
Hans Leidekker33c025b2007-04-22 11:37:51 +02004833 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
4834 if (rc != ERROR_SUCCESS)
4835 return ERROR_SUCCESS;
4836
4837 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
4838 msiobj_release(&view->hdr);
4839
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02004840 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
4841 if (rc != ERROR_SUCCESS)
4842 return ERROR_SUCCESS;
4843
4844 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
4845 msiobj_release(&view->hdr);
4846
James Hawkinsd3bec322006-11-27 18:20:33 -08004847 return rc;
4848}
4849
James Hawkins5b8641a2007-05-30 10:57:31 -07004850#define ENV_ACT_SETALWAYS 0x1
4851#define ENV_ACT_SETABSENT 0x2
4852#define ENV_ACT_REMOVE 0x4
James Hawkins881f5922007-06-13 17:46:09 -07004853#define ENV_ACT_REMOVEMATCH 0x8
James Hawkins5b8641a2007-05-30 10:57:31 -07004854
4855#define ENV_MOD_MACHINE 0x20000000
4856#define ENV_MOD_APPEND 0x40000000
4857#define ENV_MOD_PREFIX 0x80000000
James Hawkins881f5922007-06-13 17:46:09 -07004858#define ENV_MOD_MASK 0xC0000000
4859
4860#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
4861
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004862static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
James Hawkins881f5922007-06-13 17:46:09 -07004863{
4864 LPCWSTR cptr = *name;
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004865 LPCWSTR ptr = *value;
James Hawkins881f5922007-06-13 17:46:09 -07004866
4867 static const WCHAR prefix[] = {'[','~',']',0};
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004868 static const int prefix_len = 3;
James Hawkins881f5922007-06-13 17:46:09 -07004869
4870 *flags = 0;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004871 while (*cptr)
James Hawkins881f5922007-06-13 17:46:09 -07004872 {
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004873 if (*cptr == '=')
James Hawkins881f5922007-06-13 17:46:09 -07004874 *flags |= ENV_ACT_SETALWAYS;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004875 else if (*cptr == '+')
James Hawkins881f5922007-06-13 17:46:09 -07004876 *flags |= ENV_ACT_SETABSENT;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004877 else if (*cptr == '-')
James Hawkins881f5922007-06-13 17:46:09 -07004878 *flags |= ENV_ACT_REMOVE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004879 else if (*cptr == '!')
James Hawkins881f5922007-06-13 17:46:09 -07004880 *flags |= ENV_ACT_REMOVEMATCH;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004881 else if (*cptr == '*')
James Hawkins881f5922007-06-13 17:46:09 -07004882 *flags |= ENV_MOD_MACHINE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09004883 else
James Hawkins881f5922007-06-13 17:46:09 -07004884 break;
James Hawkins881f5922007-06-13 17:46:09 -07004885
4886 cptr++;
4887 (*name)++;
4888 }
4889
4890 if (!*cptr)
4891 {
4892 ERR("Missing environment variable\n");
4893 return ERROR_FUNCTION_FAILED;
4894 }
4895
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004896 if (!strncmpW(ptr, prefix, prefix_len))
James Hawkins881f5922007-06-13 17:46:09 -07004897 {
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004898 *flags |= ENV_MOD_APPEND;
James Hawkins881f5922007-06-13 17:46:09 -07004899 *value += lstrlenW(prefix);
4900 }
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004901 else if (lstrlenW(*value) >= prefix_len)
James Hawkins881f5922007-06-13 17:46:09 -07004902 {
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004903 ptr += lstrlenW(ptr) - prefix_len;
James Hawkins881f5922007-06-13 17:46:09 -07004904 if (!lstrcmpW(ptr, prefix))
4905 {
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004906 *flags |= ENV_MOD_PREFIX;
4907 /* the "[~]" will be removed by deformat_string */;
James Hawkins881f5922007-06-13 17:46:09 -07004908 }
4909 }
4910
4911 if (!*flags ||
4912 check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
4913 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
4914 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
4915 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
4916 {
4917 ERR("Invalid flags: %08x\n", *flags);
4918 return ERROR_FUNCTION_FAILED;
4919 }
4920
4921 return ERROR_SUCCESS;
4922}
James Hawkins5b8641a2007-05-30 10:57:31 -07004923
4924static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
4925{
James Hawkins881f5922007-06-13 17:46:09 -07004926 MSIPACKAGE *package = param;
4927 LPCWSTR name, value, comp;
4928 LPWSTR data = NULL, newval = NULL;
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004929 LPWSTR deformatted = NULL, ptr;
James Hawkins5b8641a2007-05-30 10:57:31 -07004930 DWORD flags, type, size;
4931 LONG res;
James Hawkins9d712382007-11-05 04:47:12 -05004932 HKEY env = NULL, root;
4933 LPCWSTR environment;
James Hawkins5b8641a2007-05-30 10:57:31 -07004934
James Hawkins9d712382007-11-05 04:47:12 -05004935 static const WCHAR user_env[] =
4936 {'E','n','v','i','r','o','n','m','e','n','t',0};
4937 static const WCHAR machine_env[] =
James Hawkins5b8641a2007-05-30 10:57:31 -07004938 {'S','y','s','t','e','m','\\',
4939 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
4940 'C','o','n','t','r','o','l','\\',
4941 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
4942 'E','n','v','i','r','o','n','m','e','n','t',0};
4943 static const WCHAR semicolon[] = {';',0};
4944
James Hawkins881f5922007-06-13 17:46:09 -07004945 name = MSI_RecordGetString(rec, 2);
4946 value = MSI_RecordGetString(rec, 3);
4947 comp = MSI_RecordGetString(rec, 4);
James Hawkins5b8641a2007-05-30 10:57:31 -07004948
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004949 res = env_set_flags(&name, &value, &flags);
James Hawkins881f5922007-06-13 17:46:09 -07004950 if (res != ERROR_SUCCESS)
4951 goto done;
4952
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07004953 deformat_string(package, value, &deformatted);
4954 if (!deformatted)
4955 {
4956 res = ERROR_OUTOFMEMORY;
4957 goto done;
4958 }
4959
James Hawkins881f5922007-06-13 17:46:09 -07004960 value = deformatted;
James Hawkins5b8641a2007-05-30 10:57:31 -07004961
4962 if (flags & ENV_MOD_MACHINE)
James Hawkins9d712382007-11-05 04:47:12 -05004963 {
4964 environment = machine_env;
James Hawkins5b8641a2007-05-30 10:57:31 -07004965 root = HKEY_LOCAL_MACHINE;
James Hawkins9d712382007-11-05 04:47:12 -05004966 }
4967 else
4968 {
4969 environment = user_env;
4970 root = HKEY_CURRENT_USER;
4971 }
James Hawkins5b8641a2007-05-30 10:57:31 -07004972
James Hawkins9d712382007-11-05 04:47:12 -05004973 res = RegCreateKeyExW(root, environment, 0, NULL, 0,
4974 KEY_ALL_ACCESS, NULL, &env, NULL);
James Hawkins5b8641a2007-05-30 10:57:31 -07004975 if (res != ERROR_SUCCESS)
James Hawkins881f5922007-06-13 17:46:09 -07004976 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07004977
4978 if (flags & ENV_ACT_REMOVE)
James Hawkins881f5922007-06-13 17:46:09 -07004979 FIXME("Not removing environment variable on uninstall!\n");
James Hawkins5b8641a2007-05-30 10:57:31 -07004980
4981 size = 0;
James Hawkins881f5922007-06-13 17:46:09 -07004982 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
4983 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
James Hawkins31c461e2008-01-05 11:46:09 -06004984 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
James Hawkins881f5922007-06-13 17:46:09 -07004985 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07004986
4987 if (res != ERROR_FILE_NOT_FOUND)
4988 {
4989 if (flags & ENV_ACT_SETABSENT)
4990 {
4991 res = ERROR_SUCCESS;
4992 goto done;
4993 }
4994
James Hawkins881f5922007-06-13 17:46:09 -07004995 data = msi_alloc(size);
4996 if (!data)
4997 {
4998 RegCloseKey(env);
4999 return ERROR_OUTOFMEMORY;
5000 }
5001
5002 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
5003 if (res != ERROR_SUCCESS)
5004 goto done;
5005
5006 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
5007 {
5008 res = RegDeleteKeyW(env, name);
5009 goto done;
5010 }
5011
5012 size = (lstrlenW(value) + 1 + size) * sizeof(WCHAR);
5013 newval = msi_alloc(size);
5014 ptr = newval;
5015 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07005016 {
5017 res = ERROR_OUTOFMEMORY;
5018 goto done;
5019 }
5020
James Hawkins881f5922007-06-13 17:46:09 -07005021 if (!(flags & ENV_MOD_MASK))
5022 lstrcpyW(newval, value);
5023 else
James Hawkins5b8641a2007-05-30 10:57:31 -07005024 {
James Hawkins881f5922007-06-13 17:46:09 -07005025 if (flags & ENV_MOD_PREFIX)
5026 {
5027 lstrcpyW(newval, value);
5028 lstrcatW(newval, semicolon);
5029 ptr = newval + lstrlenW(value) + 1;
5030 }
James Hawkins5b8641a2007-05-30 10:57:31 -07005031
James Hawkins881f5922007-06-13 17:46:09 -07005032 lstrcpyW(ptr, data);
James Hawkins5b8641a2007-05-30 10:57:31 -07005033
James Hawkins881f5922007-06-13 17:46:09 -07005034 if (flags & ENV_MOD_APPEND)
5035 {
5036 lstrcatW(newval, semicolon);
5037 lstrcatW(newval, value);
5038 }
James Hawkins5b8641a2007-05-30 10:57:31 -07005039 }
5040 }
5041 else
5042 {
5043 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
James Hawkins881f5922007-06-13 17:46:09 -07005044 newval = msi_alloc(size);
5045 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07005046 {
5047 res = ERROR_OUTOFMEMORY;
5048 goto done;
5049 }
5050
James Hawkins881f5922007-06-13 17:46:09 -07005051 lstrcpyW(newval, value);
James Hawkins5b8641a2007-05-30 10:57:31 -07005052 }
5053
James Hawkins881f5922007-06-13 17:46:09 -07005054 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
5055 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
James Hawkins5b8641a2007-05-30 10:57:31 -07005056
5057done:
Andrew Talbot0e4ccb82007-06-23 17:28:50 +01005058 if (env) RegCloseKey(env);
James Hawkins881f5922007-06-13 17:46:09 -07005059 msi_free(deformatted);
5060 msi_free(data);
5061 msi_free(newval);
James Hawkins5b8641a2007-05-30 10:57:31 -07005062 return res;
5063}
5064
5065static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
5066{
5067 UINT rc;
5068 MSIQUERY * view;
5069 static const WCHAR ExecSeqQuery[] =
5070 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5071 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
5072 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5073 if (rc != ERROR_SUCCESS)
5074 return ERROR_SUCCESS;
5075
5076 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
5077 msiobj_release(&view->hdr);
5078
5079 return rc;
5080}
5081
James Hawkinsc3df74e2007-11-01 03:09:02 -05005082#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
5083
5084typedef struct
5085{
5086 struct list entry;
5087 LPWSTR sourcename;
5088 LPWSTR destname;
5089 LPWSTR source;
5090 LPWSTR dest;
5091} FILE_LIST;
5092
5093static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options)
5094{
5095 BOOL ret;
5096
5097 if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY ||
5098 GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY)
5099 {
5100 WARN("Source or dest is directory, not moving\n");
5101 return FALSE;
5102 }
5103
5104 if (options == msidbMoveFileOptionsMove)
5105 {
5106 TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5107 ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING);
5108 if (!ret)
5109 {
5110 WARN("MoveFile failed: %d\n", GetLastError());
5111 return FALSE;
5112 }
5113 }
5114 else
5115 {
5116 TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest));
5117 ret = CopyFileW(source, dest, FALSE);
5118 if (!ret)
5119 {
5120 WARN("CopyFile failed: %d\n", GetLastError());
5121 return FALSE;
5122 }
5123 }
5124
5125 return TRUE;
5126}
5127
5128static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename)
5129{
5130 LPWSTR path, ptr;
5131 DWORD dirlen, pathlen;
5132
5133 ptr = strrchrW(wildcard, '\\');
5134 dirlen = ptr - wildcard + 1;
5135
5136 pathlen = dirlen + lstrlenW(filename) + 1;
5137 path = msi_alloc(pathlen * sizeof(WCHAR));
5138
5139 lstrcpynW(path, wildcard, dirlen + 1);
5140 lstrcatW(path, filename);
5141
5142 return path;
5143}
5144
5145static void free_file_entry(FILE_LIST *file)
5146{
5147 msi_free(file->source);
5148 msi_free(file->dest);
5149 msi_free(file);
5150}
5151
5152static void free_list(FILE_LIST *list)
5153{
5154 while (!list_empty(&list->entry))
5155 {
5156 FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry);
5157
5158 list_remove(&file->entry);
5159 free_file_entry(file);
5160 }
5161}
5162
5163static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest)
5164{
5165 FILE_LIST *new, *file;
5166 LPWSTR ptr, filename;
5167 DWORD size;
5168
5169 new = msi_alloc_zero(sizeof(FILE_LIST));
5170 if (!new)
5171 return FALSE;
5172
5173 new->source = strdupW(source);
5174 ptr = strrchrW(dest, '\\') + 1;
5175 filename = strrchrW(new->source, '\\') + 1;
5176
5177 new->sourcename = filename;
5178
5179 if (*ptr)
5180 new->destname = ptr;
5181 else
5182 new->destname = new->sourcename;
5183
5184 size = (ptr - dest) + lstrlenW(filename) + 1;
5185 new->dest = msi_alloc(size * sizeof(WCHAR));
5186 if (!new->dest)
5187 {
5188 free_file_entry(new);
5189 return FALSE;
5190 }
5191
5192 lstrcpynW(new->dest, dest, ptr - dest + 1);
5193 lstrcatW(new->dest, filename);
5194
5195 if (list_empty(&files->entry))
5196 {
5197 list_add_head(&files->entry, &new->entry);
5198 return TRUE;
5199 }
5200
5201 LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry)
5202 {
5203 if (lstrcmpW(source, file->source) < 0)
5204 {
5205 list_add_before(&file->entry, &new->entry);
5206 return TRUE;
5207 }
5208 }
5209
5210 list_add_after(&file->entry, &new->entry);
5211 return TRUE;
5212}
5213
5214BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options)
5215{
5216 WIN32_FIND_DATAW wfd;
5217 HANDLE hfile;
5218 LPWSTR path;
5219 BOOL res;
5220 FILE_LIST files, *file;
5221 DWORD size;
5222
5223 hfile = FindFirstFileW(source, &wfd);
5224 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
5225
5226 list_init(&files.entry);
5227
5228 for (res = TRUE; res; res = FindNextFileW(hfile, &wfd))
5229 {
5230 if (is_dot_dir(wfd.cFileName)) continue;
5231
5232 path = wildcard_to_file(source, wfd.cFileName);
5233 if (!path)
5234 {
James Hawkinsfa8476e2007-12-13 18:38:33 -06005235 res = FALSE;
5236 goto done;
James Hawkinsc3df74e2007-11-01 03:09:02 -05005237 }
5238
5239 add_wildcard(&files, path, dest);
5240 msi_free(path);
5241 }
5242
5243 /* only the first wildcard match gets renamed to dest */
5244 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5245 size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2;
5246 file->dest = msi_realloc(file->dest, size * sizeof(WCHAR));
5247 if (!file->dest)
5248 {
James Hawkinsfa8476e2007-12-13 18:38:33 -06005249 res = FALSE;
5250 goto done;
James Hawkinsc3df74e2007-11-01 03:09:02 -05005251 }
5252
5253 lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname);
5254
5255 while (!list_empty(&files.entry))
5256 {
5257 file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry);
5258
5259 msi_move_file((LPCWSTR)file->source, (LPCWSTR)file->dest, options);
5260
5261 list_remove(&file->entry);
5262 free_file_entry(file);
5263 }
5264
James Hawkinsfa8476e2007-12-13 18:38:33 -06005265 res = TRUE;
5266
5267done:
5268 free_list(&files);
5269 FindClose(hfile);
5270 return res;
James Hawkinsc3df74e2007-11-01 03:09:02 -05005271}
5272
5273static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
5274{
5275 MSIPACKAGE *package = param;
5276 MSICOMPONENT *comp;
5277 LPCWSTR sourcename, destname;
5278 LPWSTR sourcedir = NULL, destdir = NULL;
5279 LPWSTR source = NULL, dest = NULL;
5280 int options;
5281 DWORD size;
5282 BOOL ret, wildcards;
5283
5284 static const WCHAR backslash[] = {'\\',0};
5285
5286 comp = get_loaded_component(package, MSI_RecordGetString(rec, 2));
5287 if (!comp || !comp->Enabled ||
5288 !(comp->Action & (INSTALLSTATE_LOCAL | INSTALLSTATE_SOURCE)))
5289 {
5290 TRACE("Component not set for install, not moving file\n");
5291 return ERROR_SUCCESS;
5292 }
5293
5294 sourcename = MSI_RecordGetString(rec, 3);
5295 destname = MSI_RecordGetString(rec, 4);
5296 options = MSI_RecordGetInteger(rec, 7);
5297
5298 sourcedir = msi_dup_property(package, MSI_RecordGetString(rec, 5));
5299 if (!sourcedir)
5300 goto done;
5301
5302 destdir = msi_dup_property(package, MSI_RecordGetString(rec, 6));
5303 if (!destdir)
5304 goto done;
5305
5306 if (!sourcename)
5307 {
5308 if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES)
5309 goto done;
5310
5311 source = strdupW(sourcedir);
5312 if (!source)
5313 goto done;
5314 }
5315 else
5316 {
5317 size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2;
5318 source = msi_alloc(size * sizeof(WCHAR));
5319 if (!source)
5320 goto done;
5321
5322 lstrcpyW(source, sourcedir);
5323 if (source[lstrlenW(source) - 1] != '\\')
5324 lstrcatW(source, backslash);
5325 lstrcatW(source, sourcename);
5326 }
5327
5328 wildcards = strchrW(source, '*') || strchrW(source, '?');
5329
5330 if (!destname && !wildcards)
5331 {
5332 destname = strdupW(sourcename);
5333 if (!destname)
5334 goto done;
5335 }
5336
5337 size = 0;
5338 if (destname)
5339 size = lstrlenW(destname);
5340
5341 size += lstrlenW(destdir) + 2;
5342 dest = msi_alloc(size * sizeof(WCHAR));
5343 if (!dest)
5344 goto done;
5345
5346 lstrcpyW(dest, destdir);
5347 if (dest[lstrlenW(dest) - 1] != '\\')
5348 lstrcatW(dest, backslash);
5349
5350 if (destname)
5351 lstrcatW(dest, destname);
5352
5353 if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES)
5354 {
5355 ret = CreateDirectoryW(destdir, NULL);
5356 if (!ret)
5357 {
5358 WARN("CreateDirectory failed: %d\n", GetLastError());
5359 return ERROR_SUCCESS;
5360 }
5361 }
5362
5363 if (!wildcards)
5364 msi_move_file(source, dest, options);
5365 else
5366 move_files_wildcard(source, dest, options);
5367
5368done:
5369 msi_free(sourcedir);
5370 msi_free(destdir);
5371 msi_free(source);
5372 msi_free(dest);
5373
5374 return ERROR_SUCCESS;
5375}
5376
5377static UINT ACTION_MoveFiles( MSIPACKAGE *package )
5378{
5379 UINT rc;
5380 MSIQUERY *view;
5381
5382 static const WCHAR ExecSeqQuery[] =
5383 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5384 '`','M','o','v','e','F','i','l','e','`',0};
5385
5386 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5387 if (rc != ERROR_SUCCESS)
5388 return ERROR_SUCCESS;
5389
5390 rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package);
5391 msiobj_release(&view->hdr);
5392
5393 return rc;
5394}
5395
Mike McCormack2586a092005-09-26 09:56:18 +00005396static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
5397 LPCSTR action, LPCWSTR table )
Mike McCormack567f0312005-09-23 11:06:57 +00005398{
5399 static const WCHAR query[] = {
Mike McCormack2586a092005-09-26 09:56:18 +00005400 'S','E','L','E','C','T',' ','*',' ',
5401 'F','R','O','M',' ','`','%','s','`',0 };
Mike McCormack567f0312005-09-23 11:06:57 +00005402 MSIQUERY *view = NULL;
5403 DWORD count = 0;
Mike McCormack2586a092005-09-26 09:56:18 +00005404 UINT r;
Mike McCormack567f0312005-09-23 11:06:57 +00005405
Mike McCormack2586a092005-09-26 09:56:18 +00005406 r = MSI_OpenQuery( package->db, &view, query, table );
5407 if (r == ERROR_SUCCESS)
Mike McCormack567f0312005-09-23 11:06:57 +00005408 {
Mike McCormack2586a092005-09-26 09:56:18 +00005409 r = MSI_IterateRecords(view, &count, NULL, package);
Mike McCormack567f0312005-09-23 11:06:57 +00005410 msiobj_release(&view->hdr);
5411 }
5412
Mike McCormack2586a092005-09-26 09:56:18 +00005413 if (count)
Mike McCormackf1d46462006-10-05 13:41:22 +09005414 FIXME("%s -> %u ignored %s table values\n",
Mike McCormack2586a092005-09-26 09:56:18 +00005415 action, count, debugstr_w(table));
5416
Mike McCormack567f0312005-09-23 11:06:57 +00005417 return ERROR_SUCCESS;
5418}
Mike McCormack94fbe092005-09-23 17:21:10 +00005419
Mike McCormack55942702005-10-30 19:23:28 +00005420static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
5421{
5422 TRACE("%p\n", package);
5423 return ERROR_SUCCESS;
5424}
5425
Mike McCormack2586a092005-09-26 09:56:18 +00005426static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
Mike McCormack94fbe092005-09-23 17:21:10 +00005427{
Mike McCormack2586a092005-09-26 09:56:18 +00005428 static const WCHAR table[] =
5429 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
5430 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
Mike McCormack94fbe092005-09-23 17:21:10 +00005431}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005432
Mike McCormack2586a092005-09-26 09:56:18 +00005433static UINT ACTION_PatchFiles( MSIPACKAGE *package )
5434{
5435 static const WCHAR table[] = { 'P','a','t','c','h',0 };
5436 return msi_unimplemented_action_stub( package, "PatchFiles", table );
5437}
5438
5439static UINT ACTION_BindImage( MSIPACKAGE *package )
5440{
5441 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
5442 return msi_unimplemented_action_stub( package, "BindImage", table );
5443}
5444
5445static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
5446{
5447 static const WCHAR table[] = {
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005448 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
Mike McCormack2586a092005-09-26 09:56:18 +00005449 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
5450}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005451
Mike McCormack2586a092005-09-26 09:56:18 +00005452static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
5453{
5454 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5455 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
5456}
5457
5458static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
5459{
5460 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
5461 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
5462}
5463
Mike McCormack2586a092005-09-26 09:56:18 +00005464static UINT ACTION_StopServices( MSIPACKAGE *package )
5465{
5466 static const WCHAR table[] = {
5467 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5468 return msi_unimplemented_action_stub( package, "StopServices", table );
5469}
5470
5471static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5472{
5473 static const WCHAR table[] = {
5474 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5475 return msi_unimplemented_action_stub( package, "DeleteServices", table );
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00005476}
Steven Steinee3ac7a2007-02-11 19:51:03 -05005477static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
5478{
5479 static const WCHAR table[] = {
5480 'P','r','o','d','u','c','t','I','D',0 };
5481 return msi_unimplemented_action_stub( package, "ValidateProductID", table );
5482}
Mike McCormack3b955152005-09-28 18:10:44 +00005483
Mike McCormack3b955152005-09-28 18:10:44 +00005484static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
5485{
5486 static const WCHAR table[] = {
5487 'E','n','v','i','r','o','n','m','e','n','t',0 };
5488 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
5489}
5490
5491static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
5492{
5493 static const WCHAR table[] = {
5494 'M','s','i','A','s','s','e','m','b','l','y',0 };
5495 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
5496}
5497
5498static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
5499{
5500 static const WCHAR table[] = {
5501 'M','s','i','A','s','s','e','m','b','l','y',0 };
5502 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
5503}
5504
5505static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
5506{
5507 static const WCHAR table[] = { 'F','o','n','t',0 };
5508 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
5509}
5510
Mike McCormackf24a9e22005-12-31 13:14:23 +01005511static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
5512{
5513 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
5514 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
5515}
5516
Mike McCormack88603662006-03-22 23:01:56 +09005517static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
5518{
5519 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5520 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
5521}
5522
5523static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
5524{
5525 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
5526 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
5527}
5528
James Hawkins987c2c82007-05-06 20:52:14 -05005529static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
5530{
5531 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
5532 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
5533}
5534
5535static UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package )
5536{
5537 static const WCHAR table[] = { 'D','u','p','l','i','c','a','t','e','F','i','l','e',0 };
5538 return msi_unimplemented_action_stub( package, "RemoveDuplicateFiles", table );
5539}
5540
5541static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
5542{
5543 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
5544 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
5545}
5546
5547static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
5548{
5549 static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 };
5550 return msi_unimplemented_action_stub( package, "RemoveFolders", table );
5551}
5552
5553static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
5554{
5555 static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 };
5556 return msi_unimplemented_action_stub( package, "RemoveODBC", table );
5557}
5558
5559static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
5560{
5561 static const WCHAR table[] = { 'R','e','m','o','v','e','R','e','g','i','s','t','r','y',0 };
5562 return msi_unimplemented_action_stub( package, "RemoveRegistryValues", table );
5563}
5564
5565static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
5566{
5567 static const WCHAR table[] = { 'S','h','o','r','t','c','u','t',0 };
5568 return msi_unimplemented_action_stub( package, "RemoveShortcuts", table );
5569}
5570
5571static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5572{
5573 static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 };
5574 return msi_unimplemented_action_stub( package, "UnpublishComponents", table );
5575}
5576
James Hawkins987c2c82007-05-06 20:52:14 -05005577static UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
5578{
5579 static const WCHAR table[] = { 'A','p','p','I','d',0 };
5580 return msi_unimplemented_action_stub( package, "UnregisterClassInfo", table );
5581}
5582
5583static UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
5584{
5585 static const WCHAR table[] = { 'E','x','t','e','n','s','i','o','n',0 };
5586 return msi_unimplemented_action_stub( package, "UnregisterExtensionInfo", table );
5587}
5588
5589static UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
5590{
5591 static const WCHAR table[] = { 'M','I','M','E',0 };
5592 return msi_unimplemented_action_stub( package, "UnregisterMIMEInfo", table );
5593}
5594
5595static UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
5596{
5597 static const WCHAR table[] = { 'P','r','o','g','I','d',0 };
5598 return msi_unimplemented_action_stub( package, "UnregisterProgIdInfo", table );
5599}
5600
5601static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
5602{
5603 static const WCHAR table[] = { 'T','y','p','e','L','i','b',0 };
5604 return msi_unimplemented_action_stub( package, "UnregisterTypeLibraries", table );
5605}
5606
Dmitry Timoshkov1cdf5cd2006-11-29 18:03:14 +08005607static const struct _actions StandardActions[] = {
Mike McCormack55942702005-10-30 19:23:28 +00005608 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
Mike McCormack3b955152005-09-28 18:10:44 +00005609 { szAppSearch, ACTION_AppSearch },
5610 { szBindImage, ACTION_BindImage },
James Hawkins987c2c82007-05-06 20:52:14 -05005611 { szCCPSearch, ACTION_CCPSearch },
Mike McCormack3b955152005-09-28 18:10:44 +00005612 { szCostFinalize, ACTION_CostFinalize },
5613 { szCostInitialize, ACTION_CostInitialize },
5614 { szCreateFolders, ACTION_CreateFolders },
5615 { szCreateShortcuts, ACTION_CreateShortcuts },
5616 { szDeleteServices, ACTION_DeleteServices },
James Hawkins987c2c82007-05-06 20:52:14 -05005617 { szDisableRollback, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005618 { szDuplicateFiles, ACTION_DuplicateFiles },
5619 { szExecuteAction, ACTION_ExecuteAction },
5620 { szFileCost, ACTION_FileCost },
5621 { szFindRelatedProducts, ACTION_FindRelatedProducts },
5622 { szForceReboot, ACTION_ForceReboot },
James Hawkins987c2c82007-05-06 20:52:14 -05005623 { szInstallAdminPackage, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005624 { szInstallExecute, ACTION_InstallExecute },
5625 { szInstallExecuteAgain, ACTION_InstallExecute },
5626 { szInstallFiles, ACTION_InstallFiles},
5627 { szInstallFinalize, ACTION_InstallFinalize },
5628 { szInstallInitialize, ACTION_InstallInitialize },
James Hawkins987c2c82007-05-06 20:52:14 -05005629 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
Mike McCormack3b955152005-09-28 18:10:44 +00005630 { szInstallValidate, ACTION_InstallValidate },
5631 { szIsolateComponents, ACTION_IsolateComponents },
5632 { szLaunchConditions, ACTION_LaunchConditions },
5633 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
5634 { szMoveFiles, ACTION_MoveFiles },
5635 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
5636 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
James Hawkinsd3bec322006-11-27 18:20:33 -08005637 { szInstallODBC, ACTION_InstallODBC },
Mike McCormack3b955152005-09-28 18:10:44 +00005638 { szInstallServices, ACTION_InstallServices },
5639 { szPatchFiles, ACTION_PatchFiles },
5640 { szProcessComponents, ACTION_ProcessComponents },
5641 { szPublishComponents, ACTION_PublishComponents },
5642 { szPublishFeatures, ACTION_PublishFeatures },
5643 { szPublishProduct, ACTION_PublishProduct },
5644 { szRegisterClassInfo, ACTION_RegisterClassInfo },
Mike McCormack88603662006-03-22 23:01:56 +09005645 { szRegisterComPlus, ACTION_RegisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00005646 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
5647 { szRegisterFonts, ACTION_RegisterFonts },
5648 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
5649 { szRegisterProduct, ACTION_RegisterProduct },
5650 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
5651 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
James Hawkins987c2c82007-05-06 20:52:14 -05005652 { szRegisterUser, ACTION_RegisterUser },
5653 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
Mike McCormack3b955152005-09-28 18:10:44 +00005654 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
James Hawkins987c2c82007-05-06 20:52:14 -05005655 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
5656 { szRemoveFiles, ACTION_RemoveFiles },
5657 { szRemoveFolders, ACTION_RemoveFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00005658 { szRemoveIniValues, ACTION_RemoveIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05005659 { szRemoveODBC, ACTION_RemoveODBC },
5660 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
5661 { szRemoveShortcuts, ACTION_RemoveShortcuts },
5662 { szResolveSource, ACTION_ResolveSource },
5663 { szRMCCPSearch, ACTION_RMCCPSearch },
5664 { szScheduleReboot, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005665 { szSelfRegModules, ACTION_SelfRegModules },
5666 { szSelfUnregModules, ACTION_SelfUnregModules },
James Hawkins987c2c82007-05-06 20:52:14 -05005667 { szSetODBCFolders, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005668 { szStartServices, ACTION_StartServices },
5669 { szStopServices, ACTION_StopServices },
James Hawkins987c2c82007-05-06 20:52:14 -05005670 { szUnpublishComponents, ACTION_UnpublishComponents },
5671 { szUnpublishFeatures, ACTION_UnpublishFeatures },
5672 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
5673 { szUnregisterComPlus, ACTION_UnregisterComPlus },
5674 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
Mike McCormack3b955152005-09-28 18:10:44 +00005675 { szUnregisterFonts, ACTION_UnregisterFonts },
James Hawkins987c2c82007-05-06 20:52:14 -05005676 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
5677 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
5678 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
5679 { szValidateProductID, ACTION_ValidateProductID },
Mike McCormack3b955152005-09-28 18:10:44 +00005680 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
5681 { szWriteIniValues, ACTION_WriteIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05005682 { szWriteRegistryValues, ACTION_WriteRegistryValues },
5683 { NULL, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00005684};