blob: a90a81a8b52fc4b9f45a45ec46a9dd3922857481 [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
Mike McCormacke3452222005-09-28 15:12:32 +0000296static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
297{
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{
457 static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
458 LPWSTR guid_list, *guids, product_id;
459 UINT i, ret = ERROR_FUNCTION_FAILED;
460
461 product_id = msi_dup_property( package, szProdID );
462 if (!product_id)
463 {
464 /* FIXME: the property ProductID should be written into the DB somewhere */
465 ERR("no product ID to check\n");
466 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 {
473 if (!lstrcmpW( guids[i], product_id ))
474 ret = ERROR_SUCCESS;
475 }
476 msi_free( guids );
477 msi_free( guid_list );
478 msi_free( product_id );
479
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
Aric Stewart401bd3f2004-06-28 20:34:35 +0000587/****************************************************
588 * TOP level entry points
589 *****************************************************/
590
Mike McCormack61f24a42005-09-30 10:32:41 +0000591UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
592 LPCWSTR szCommandLine )
Aric Stewart401bd3f2004-06-28 20:34:35 +0000593{
Aric Stewart401bd3f2004-06-28 20:34:35 +0000594 UINT rc;
Aric Stewartf8f64402005-03-24 19:03:45 +0000595 BOOL ui = FALSE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000596 static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
Aric Stewart6269f002005-01-17 13:40:39 +0000597 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
598 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
599
600 MSI_SetPropertyW(package, szAction, szInstall);
Aric Stewart9cd707d2005-05-27 19:24:22 +0000601
Mike McCormack3a940112006-04-19 02:29:03 +0900602 package->script = msi_alloc_zero(sizeof(MSISCRIPT));
Aric Stewart401bd3f2004-06-28 20:34:35 +0000603
Aric Stewartc9802932005-06-30 20:45:43 +0000604 package->script->InWhatSequence = SEQUENCE_INSTALL;
605
Aric Stewarte95136b2004-06-29 03:44:01 +0000606 if (szPackagePath)
607 {
Mike McCormackba8200b2004-12-22 15:25:30 +0000608 LPWSTR p, check, path;
Aric Stewarte95136b2004-06-29 03:44:01 +0000609
Mike McCormack95dea492005-03-16 11:31:35 +0000610 path = strdupW(szPackagePath);
Mike McCormackba8200b2004-12-22 15:25:30 +0000611 p = strrchrW(path,'\\');
Aric Stewarte95136b2004-06-29 03:44:01 +0000612 if (p)
613 {
614 p++;
615 *p=0;
616 }
Aric Stewartc1e5c4a2005-02-08 14:26:49 +0000617 else
618 {
Mike McCormackee034ba2005-09-20 11:59:14 +0000619 msi_free(path);
620 path = msi_alloc(MAX_PATH*sizeof(WCHAR));
Aric Stewartc1e5c4a2005-02-08 14:26:49 +0000621 GetCurrentDirectoryW(MAX_PATH,path);
622 strcatW(path,cszbs);
623 }
Aric Stewarte95136b2004-06-29 03:44:01 +0000624
Mike McCormack062ad502005-09-15 15:04:08 +0000625 check = msi_dup_property( package, cszSourceDir );
Aric Stewartd0c971a2004-12-22 18:15:50 +0000626 if (!check)
Mike McCormackba8200b2004-12-22 15:25:30 +0000627 MSI_SetPropertyW(package, cszSourceDir, path);
Mike McCormack063c42c2006-11-08 14:55:31 +0900628 msi_free(check);
James Hawkinsc5075432006-10-10 13:39:50 -0700629
James Hawkins3797e6c2006-10-13 14:08:52 -0700630 check = msi_dup_property( package, cszSOURCEDIR );
631 if (!check)
632 MSI_SetPropertyW(package, cszSOURCEDIR, path);
633
Mike McCormack4047cc72006-10-17 16:11:42 +0900634 msi_free( package->PackagePath );
James Hawkinsc5075432006-10-10 13:39:50 -0700635 package->PackagePath = path;
636
Mike McCormackee034ba2005-09-20 11:59:14 +0000637 msi_free(check);
Aric Stewarte95136b2004-06-29 03:44:01 +0000638 }
Aric Stewart401bd3f2004-06-28 20:34:35 +0000639
Mike McCormacke3452222005-09-28 15:12:32 +0000640 msi_parse_command_line( package, szCommandLine );
Mike McCormack74f0de92005-09-29 10:32:39 +0000641
Mike McCormacke534e772006-01-04 14:51:25 +0100642 msi_apply_transforms( package );
Mike McCormack965a72a2005-10-26 12:06:21 +0000643 msi_apply_patches( package );
644
Mike McCormack74f0de92005-09-29 10:32:39 +0000645 if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000646 {
Mike McCormack74f0de92005-09-29 10:32:39 +0000647 package->script->InWhatSequence |= SEQUENCE_UI;
648 rc = ACTION_ProcessUISequence(package);
649 ui = TRUE;
650 if (rc == ERROR_SUCCESS)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000651 {
Mike McCormack74f0de92005-09-29 10:32:39 +0000652 package->script->InWhatSequence |= SEQUENCE_EXEC;
653 rc = ACTION_ProcessExecSequence(package,TRUE);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000654 }
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000655 }
656 else
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000657 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewart6b16f292005-01-27 11:12:56 +0000658
659 if (rc == -1)
660 {
661 /* install was halted but should be considered a success */
662 rc = ERROR_SUCCESS;
663 }
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000664
Aric Stewart9cd707d2005-05-27 19:24:22 +0000665 package->script->CurrentlyScripting= FALSE;
666
Aric Stewart09d35c32004-12-27 19:00:26 +0000667 /* process the ending type action */
668 if (rc == ERROR_SUCCESS)
Aric Stewartf8f64402005-03-24 19:03:45 +0000669 ACTION_PerformActionSequence(package,-1,ui);
Aric Stewart6b16f292005-01-27 11:12:56 +0000670 else if (rc == ERROR_INSTALL_USEREXIT)
Aric Stewartf8f64402005-03-24 19:03:45 +0000671 ACTION_PerformActionSequence(package,-2,ui);
Aric Stewart6b16f292005-01-27 11:12:56 +0000672 else if (rc == ERROR_INSTALL_SUSPEND)
Aric Stewartf8f64402005-03-24 19:03:45 +0000673 ACTION_PerformActionSequence(package,-4,ui);
Aric Stewart9cd707d2005-05-27 19:24:22 +0000674 else /* failed */
675 ACTION_PerformActionSequence(package,-3,ui);
Aric Stewart54c67dd2005-01-25 20:17:09 +0000676
677 /* finish up running custom actions */
678 ACTION_FinishCustomActions(package);
Aric Stewart09d35c32004-12-27 19:00:26 +0000679
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000680 return rc;
681}
682
Aric Stewartf8f64402005-03-24 19:03:45 +0000683static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
Aric Stewart09d35c32004-12-27 19:00:26 +0000684{
Mike McCormack0b352c72005-06-02 10:29:57 +0000685 UINT rc = ERROR_SUCCESS;
Aric Stewart09d35c32004-12-27 19:00:26 +0000686 MSIRECORD * row = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +0000687 static const WCHAR ExecSeqQuery[] =
688 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000689 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
690 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
691 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
Aric Stewart09d35c32004-12-27 19:00:26 +0000692
Aric Stewartf8f64402005-03-24 19:03:45 +0000693 static const WCHAR UISeqQuery[] =
694 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000695 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
696 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
Aric Stewartf8f64402005-03-24 19:03:45 +0000697 ' ', '=',' ','%','i',0};
698
699 if (UI)
Mike McCormack0b352c72005-06-02 10:29:57 +0000700 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
Aric Stewartf8f64402005-03-24 19:03:45 +0000701 else
Mike McCormack0b352c72005-06-02 10:29:57 +0000702 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
Aric Stewart09d35c32004-12-27 19:00:26 +0000703
Mike McCormack0b352c72005-06-02 10:29:57 +0000704 if (row)
Aric Stewart09d35c32004-12-27 19:00:26 +0000705 {
Mike McCormack20806c72005-06-07 21:34:05 +0000706 LPCWSTR action, cond;
707
Aric Stewart09d35c32004-12-27 19:00:26 +0000708 TRACE("Running the actions\n");
709
Aric Stewart09d35c32004-12-27 19:00:26 +0000710 /* check conditions */
Mike McCormack20806c72005-06-07 21:34:05 +0000711 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900712
713 /* this is a hack to skip errors in the condition code */
714 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
715 goto end;
Aric Stewart09d35c32004-12-27 19:00:26 +0000716
Mike McCormack20806c72005-06-07 21:34:05 +0000717 action = MSI_RecordGetString(row,1);
718 if (!action)
Aric Stewart09d35c32004-12-27 19:00:26 +0000719 {
Mike McCormack20806c72005-06-07 21:34:05 +0000720 ERR("failed to fetch action\n");
721 rc = ERROR_FUNCTION_FAILED;
Aric Stewart09d35c32004-12-27 19:00:26 +0000722 goto end;
723 }
724
Aric Stewartf8f64402005-03-24 19:03:45 +0000725 if (UI)
Mike McCormack20806c72005-06-07 21:34:05 +0000726 rc = ACTION_PerformUIAction(package,action);
Aric Stewartf8f64402005-03-24 19:03:45 +0000727 else
Mike McCormack20806c72005-06-07 21:34:05 +0000728 rc = ACTION_PerformAction(package,action,FALSE);
Aric Stewart09d35c32004-12-27 19:00:26 +0000729end:
Mike McCormack0b352c72005-06-02 10:29:57 +0000730 msiobj_release(&row->hdr);
Aric Stewart09d35c32004-12-27 19:00:26 +0000731 }
732 else
733 rc = ERROR_SUCCESS;
734
735 return rc;
736}
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000737
Aric Stewart2703d712005-06-20 15:33:10 +0000738typedef struct {
739 MSIPACKAGE* package;
740 BOOL UI;
741} iterate_action_param;
742
743static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
744{
745 iterate_action_param *iap= (iterate_action_param*)param;
746 UINT rc;
747 LPCWSTR cond, action;
748
749 action = MSI_RecordGetString(row,1);
750 if (!action)
751 {
752 ERR("Error is retrieving action name\n");
Mike McCormack9375fd92006-10-27 17:29:02 +0900753 return ERROR_FUNCTION_FAILED;
Aric Stewart2703d712005-06-20 15:33:10 +0000754 }
755
756 /* check conditions */
757 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900758
759 /* this is a hack to skip errors in the condition code */
760 if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
Aric Stewart2703d712005-06-20 15:33:10 +0000761 {
Mike McCormack9375fd92006-10-27 17:29:02 +0900762 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
763 return ERROR_SUCCESS;
Aric Stewart2703d712005-06-20 15:33:10 +0000764 }
765
766 if (iap->UI)
767 rc = ACTION_PerformUIAction(iap->package,action);
768 else
769 rc = ACTION_PerformAction(iap->package,action,FALSE);
770
Mike McCormack4f634a32005-07-06 15:44:51 +0000771 msi_dialog_check_messages( NULL );
772
773 if (iap->package->CurrentInstallState != ERROR_SUCCESS )
774 rc = iap->package->CurrentInstallState;
775
Aric Stewart2703d712005-06-20 15:33:10 +0000776 if (rc == ERROR_FUNCTION_NOT_CALLED)
777 rc = ERROR_SUCCESS;
778
779 if (rc != ERROR_SUCCESS)
Mike McCormack558abec2005-10-27 12:39:28 +0000780 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
Aric Stewart2703d712005-06-20 15:33:10 +0000781
782 return rc;
783}
784
Mike McCormackd34b1c22005-09-21 10:55:23 +0000785UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
786{
787 MSIQUERY * view;
788 UINT r;
789 static const WCHAR query[] =
790 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
791 '`','%','s','`',
792 ' ','W','H','E','R','E',' ',
793 '`','S','e','q','u','e','n','c','e','`',' ',
794 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
795 '`','S','e','q','u','e','n','c','e','`',0};
796 iterate_action_param iap;
797
798 /*
799 * FIXME: probably should be checking UILevel in the
800 * ACTION_PerformUIAction/ACTION_PerformAction
801 * rather than saving the UI level here. Those
802 * two functions can be merged too.
803 */
804 iap.package = package;
805 iap.UI = TRUE;
806
807 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
808
809 r = MSI_OpenQuery( package->db, &view, query, szTable );
810 if (r == ERROR_SUCCESS)
811 {
812 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
813 msiobj_release(&view->hdr);
814 }
815
816 return r;
817}
818
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000819static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000820{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000821 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000822 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000823 static const WCHAR ExecSeqQuery[] =
824 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000825 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
826 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
827 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000828 'O','R','D','E','R',' ', 'B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000829 '`','S','e','q','u','e','n','c','e','`',0 };
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000830 MSIRECORD * row = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +0000831 static const WCHAR IVQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +0000832 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
833 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
834 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
835 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
836 ' ','\'', 'I','n','s','t','a','l','l',
837 'V','a','l','i','d','a','t','e','\'', 0};
Mike McCormack9db0e072004-12-22 15:05:07 +0000838 INT seq = 0;
Aric Stewart2703d712005-06-20 15:33:10 +0000839 iterate_action_param iap;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000840
Aric Stewart2703d712005-06-20 15:33:10 +0000841 iap.package = package;
842 iap.UI = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000843
Aric Stewart9cd707d2005-05-27 19:24:22 +0000844 if (package->script->ExecuteSequenceRun)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000845 {
846 TRACE("Execute Sequence already Run\n");
847 return ERROR_SUCCESS;
848 }
849
Aric Stewart9cd707d2005-05-27 19:24:22 +0000850 package->script->ExecuteSequenceRun = TRUE;
Aric Stewart2703d712005-06-20 15:33:10 +0000851
Mike McCormack9db0e072004-12-22 15:05:07 +0000852 /* get the sequence number */
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000853 if (UIran)
854 {
Mike McCormack0b352c72005-06-02 10:29:57 +0000855 row = MSI_QueryGetRecord(package->db, IVQuery);
856 if( !row )
857 return ERROR_FUNCTION_FAILED;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000858 seq = MSI_RecordGetInteger(row,1);
859 msiobj_release(&row->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000860 }
Mike McCormack9db0e072004-12-22 15:05:07 +0000861
Mike McCormack0c238852005-01-21 16:19:11 +0000862 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000863 if (rc == ERROR_SUCCESS)
864 {
Aric Stewart2703d712005-06-20 15:33:10 +0000865 TRACE("Running the actions\n");
Aric Stewart401bd3f2004-06-28 20:34:35 +0000866
Aric Stewart2703d712005-06-20 15:33:10 +0000867 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000868 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000869 }
870
Aric Stewart401bd3f2004-06-28 20:34:35 +0000871 return rc;
872}
873
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000874static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000875{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000876 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000877 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000878 static const WCHAR ExecSeqQuery [] =
879 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000880 '`','I','n','s','t','a','l','l',
881 'U','I','S','e','q','u','e','n','c','e','`',
882 ' ','W','H','E','R','E',' ',
883 '`','S','e','q','u','e','n','c','e','`',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000884 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000885 '`','S','e','q','u','e','n','c','e','`',0};
Aric Stewart2703d712005-06-20 15:33:10 +0000886 iterate_action_param iap;
887
888 iap.package = package;
889 iap.UI = TRUE;
890
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000891 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000892
893 if (rc == ERROR_SUCCESS)
894 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000895 TRACE("Running the actions\n");
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000896
Aric Stewart2703d712005-06-20 15:33:10 +0000897 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000898 msiobj_release(&view->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000899 }
900
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000901 return rc;
902}
903
Aric Stewart401bd3f2004-06-28 20:34:35 +0000904/********************************************************
905 * ACTION helper functions and functions that perform the actions
906 *******************************************************/
Aric Stewart9cd707d2005-05-27 19:24:22 +0000907static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
908 UINT* rc, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +0000909{
910 BOOL ret = FALSE;
Aric Stewart9cd707d2005-05-27 19:24:22 +0000911 BOOL run = force;
Aric Stewart3f318602005-02-01 18:46:26 +0000912 int i;
Aric Stewart9cd707d2005-05-27 19:24:22 +0000913
914 if (!run && !package->script->CurrentlyScripting)
915 run = TRUE;
916
917 if (!run)
918 {
919 if (strcmpW(action,szInstallFinalize) == 0 ||
920 strcmpW(action,szInstallExecute) == 0 ||
921 strcmpW(action,szInstallExecuteAgain) == 0)
922 run = TRUE;
923 }
924
Aric Stewart3f318602005-02-01 18:46:26 +0000925 i = 0;
926 while (StandardActions[i].action != NULL)
927 {
928 if (strcmpW(StandardActions[i].action, action)==0)
929 {
Aric Stewart9cd707d2005-05-27 19:24:22 +0000930 if (!run)
Aric Stewartd6ecf582005-02-02 09:29:30 +0000931 {
Aric Stewart9cd707d2005-05-27 19:24:22 +0000932 ui_actioninfo(package, action, TRUE, 0);
933 *rc = schedule_action(package,INSTALL_SCRIPT,action);
934 ui_actioninfo(package, action, FALSE, *rc);
Aric Stewartd6ecf582005-02-02 09:29:30 +0000935 }
936 else
937 {
Aric Stewart9cd707d2005-05-27 19:24:22 +0000938 ui_actionstart(package, action);
939 if (StandardActions[i].handler)
940 {
941 *rc = StandardActions[i].handler(package);
942 }
943 else
944 {
Mike McCormack54a28912005-09-06 09:23:18 +0000945 FIXME("unhandled standard action %s\n",debugstr_w(action));
Aric Stewart9cd707d2005-05-27 19:24:22 +0000946 *rc = ERROR_SUCCESS;
947 }
Aric Stewartd6ecf582005-02-02 09:29:30 +0000948 }
Aric Stewart3f318602005-02-01 18:46:26 +0000949 ret = TRUE;
950 break;
951 }
952 i++;
953 }
954 return ret;
955}
956
Mike McCormackf9acfe62005-06-07 20:29:51 +0000957static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
958 UINT* rc, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +0000959{
960 BOOL ret=FALSE;
961 UINT arc;
962
Aric Stewart9cd707d2005-05-27 19:24:22 +0000963 arc = ACTION_CustomAction(package,action, force);
Aric Stewart3f318602005-02-01 18:46:26 +0000964
965 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
966 {
967 *rc = arc;
968 ret = TRUE;
969 }
970 return ret;
971}
Aric Stewart401bd3f2004-06-28 20:34:35 +0000972
973/*
Francois Gougetda8b3dd2005-01-26 21:09:04 +0000974 * A lot of actions are really important even if they don't do anything
975 * explicit... Lots of properties are set at the beginning of the installation
976 * CostFinalize does a bunch of work to translate the directories and such
Aric Stewart401bd3f2004-06-28 20:34:35 +0000977 *
Mike McCormack6e2bca32004-07-04 00:25:00 +0000978 * But until I get write access to the database that is hard, so I am going to
Aric Stewart401bd3f2004-06-28 20:34:35 +0000979 * hack it to see if I can get something to run.
980 */
Aric Stewart9cd707d2005-05-27 19:24:22 +0000981UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
Aric Stewart401bd3f2004-06-28 20:34:35 +0000982{
Aric Stewartd2c395a2004-07-06 18:48:15 +0000983 UINT rc = ERROR_SUCCESS;
Aric Stewart3f318602005-02-01 18:46:26 +0000984 BOOL handled;
Aric Stewart401bd3f2004-06-28 20:34:35 +0000985
986 TRACE("Performing action (%s)\n",debugstr_w(action));
987
Aric Stewart9cd707d2005-05-27 19:24:22 +0000988 handled = ACTION_HandleStandardAction(package, action, &rc, force);
Aric Stewart7d3e5972004-07-04 00:36:58 +0000989
Aric Stewart3f318602005-02-01 18:46:26 +0000990 if (!handled)
Aric Stewart9cd707d2005-05-27 19:24:22 +0000991 handled = ACTION_HandleCustomAction(package, action, &rc, force);
Aric Stewart3f318602005-02-01 18:46:26 +0000992
Aric Stewart90c57392005-01-31 16:23:12 +0000993 if (!handled)
994 {
Mike McCormack54a28912005-09-06 09:23:18 +0000995 FIXME("unhandled msi action %s\n",debugstr_w(action));
Aric Stewart3f318602005-02-01 18:46:26 +0000996 rc = ERROR_FUNCTION_NOT_CALLED;
997 }
Aric Stewart7d3e5972004-07-04 00:36:58 +0000998
Aric Stewart3f318602005-02-01 18:46:26 +0000999 return rc;
1000}
1001
1002UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1003{
1004 UINT rc = ERROR_SUCCESS;
1005 BOOL handled = FALSE;
1006
1007 TRACE("Performing action (%s)\n",debugstr_w(action));
1008
Aric Stewart9cd707d2005-05-27 19:24:22 +00001009 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
Aric Stewart3f318602005-02-01 18:46:26 +00001010
1011 if (!handled)
Aric Stewart9cd707d2005-05-27 19:24:22 +00001012 handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
Aric Stewart3f318602005-02-01 18:46:26 +00001013
Mike McCormack4f634a32005-07-06 15:44:51 +00001014 if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1015 handled = TRUE;
Mike McCormack34d4a022005-02-09 13:24:31 +00001016
Aric Stewart3f318602005-02-01 18:46:26 +00001017 if (!handled)
1018 {
Mike McCormack54a28912005-09-06 09:23:18 +00001019 FIXME("unhandled msi action %s\n",debugstr_w(action));
Aric Stewart3f318602005-02-01 18:46:26 +00001020 rc = ERROR_FUNCTION_NOT_CALLED;
Aric Stewart90c57392005-01-31 16:23:12 +00001021 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00001022
Aric Stewartd2c395a2004-07-06 18:48:15 +00001023 return rc;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001024}
1025
Aric Stewart2274ff12005-06-21 20:03:46 +00001026
1027/*
1028 * Actual Action Handlers
1029 */
1030
1031static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1032{
1033 MSIPACKAGE *package = (MSIPACKAGE*)param;
1034 LPCWSTR dir;
1035 LPWSTR full_path;
1036 MSIRECORD *uirow;
1037 MSIFOLDER *folder;
1038
1039 dir = MSI_RecordGetString(row,1);
1040 if (!dir)
1041 {
Francois Gouget0edbaf72005-11-10 12:14:56 +00001042 ERR("Unable to get folder id\n");
Aric Stewart2274ff12005-06-21 20:03:46 +00001043 return ERROR_SUCCESS;
1044 }
1045
1046 full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1047 if (!full_path)
1048 {
1049 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1050 return ERROR_SUCCESS;
1051 }
1052
1053 TRACE("Folder is %s\n",debugstr_w(full_path));
1054
1055 /* UI stuff */
1056 uirow = MSI_CreateRecord(1);
1057 MSI_RecordSetStringW(uirow,1,full_path);
1058 ui_actiondata(package,szCreateFolders,uirow);
1059 msiobj_release( &uirow->hdr );
1060
1061 if (folder->State == 0)
1062 create_full_pathW(full_path);
1063
1064 folder->State = 3;
1065
Mike McCormackee034ba2005-09-20 11:59:14 +00001066 msi_free(full_path);
Aric Stewart2274ff12005-06-21 20:03:46 +00001067 return ERROR_SUCCESS;
1068}
1069
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001070/* FIXME: probably should merge this with the above function */
1071static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1072{
1073 UINT rc = ERROR_SUCCESS;
1074 MSIFOLDER *folder;
1075 LPWSTR install_path;
1076
1077 install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1078 if (!install_path)
1079 return ERROR_FUNCTION_FAILED;
1080
1081 /* create the path */
1082 if (folder->State == 0)
1083 {
1084 create_full_pathW(install_path);
1085 folder->State = 2;
1086 }
1087 msi_free(install_path);
1088
1089 return rc;
1090}
Aric Stewart2274ff12005-06-21 20:03:46 +00001091
Mike McCormack9c845852005-10-29 11:29:17 +00001092UINT msi_create_component_directories( MSIPACKAGE *package )
1093{
1094 MSICOMPONENT *comp;
1095
1096 /* create all the folders required by the components are going to install */
1097 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1098 {
Mike McCormackd693f462005-10-29 11:36:48 +00001099 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Mike McCormack9c845852005-10-29 11:29:17 +00001100 continue;
1101 msi_create_directory( package, comp->Directory );
1102 }
1103
1104 return ERROR_SUCCESS;
1105}
1106
Aric Stewart401bd3f2004-06-28 20:34:35 +00001107/*
1108 * Also we cannot enable/disable components either, so for now I am just going
Mike McCormack6e2bca32004-07-04 00:25:00 +00001109 * to do all the directories for all the components.
Aric Stewart401bd3f2004-06-28 20:34:35 +00001110 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001111static UINT ACTION_CreateFolders(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00001112{
Aric Stewart8e233e92005-03-01 11:45:19 +00001113 static const WCHAR ExecSeqQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001114 {'S','E','L','E','C','T',' ',
1115 '`','D','i','r','e','c','t','o','r','y','_','`',
Aric Stewart8e233e92005-03-01 11:45:19 +00001116 ' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001117 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00001118 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001119 MSIQUERY *view;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001120
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001121 /* create all the empty folders specified in the CreateFolder table */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001122 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
Aric Stewart401bd3f2004-06-28 20:34:35 +00001123 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00001124 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001125
Aric Stewart2274ff12005-06-21 20:03:46 +00001126 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001127 msiobj_release(&view->hdr);
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001128
Mike McCormack9c845852005-10-29 11:29:17 +00001129 msi_create_component_directories( package );
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001130
Aric Stewart401bd3f2004-06-28 20:34:35 +00001131 return rc;
1132}
1133
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001134static UINT load_component( MSIRECORD *row, LPVOID param )
Aric Stewartbdb29552004-07-04 00:32:48 +00001135{
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001136 MSIPACKAGE *package = param;
Mike McCormack38d67a42005-08-22 09:15:23 +00001137 MSICOMPONENT *comp;
Aric Stewartbdb29552004-07-04 00:32:48 +00001138
Mike McCormackee034ba2005-09-20 11:59:14 +00001139 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
Mike McCormack38d67a42005-08-22 09:15:23 +00001140 if (!comp)
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001141 return ERROR_FUNCTION_FAILED;
1142
1143 list_add_tail( &package->components, &comp->entry );
Mike McCormack38d67a42005-08-22 09:15:23 +00001144
Aric Stewartbdb29552004-07-04 00:32:48 +00001145 /* fill in the data */
Mike McCormack51c66182005-10-27 12:36:12 +00001146 comp->Component = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001147
Mike McCormackefcc1ec2005-09-12 12:07:15 +00001148 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
Aric Stewartbdb29552004-07-04 00:32:48 +00001149
Mike McCormack51c66182005-10-27 12:36:12 +00001150 comp->ComponentId = msi_dup_record_field( row, 2 );
1151 comp->Directory = msi_dup_record_field( row, 3 );
Mike McCormack38d67a42005-08-22 09:15:23 +00001152 comp->Attributes = MSI_RecordGetInteger(row,4);
Mike McCormack51c66182005-10-27 12:36:12 +00001153 comp->Condition = msi_dup_record_field( row, 5 );
1154 comp->KeyPath = msi_dup_record_field( row, 6 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001155
James Hawkinsd893cb72006-09-20 19:55:01 -07001156 comp->Installed = INSTALLSTATE_UNKNOWN;
Mike McCormack575cc672006-10-26 14:09:29 +09001157 msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
Aric Stewartfbdd7092004-12-27 19:06:22 +00001158
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001159 return ERROR_SUCCESS;
1160}
Aric Stewartbdb29552004-07-04 00:32:48 +00001161
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001162static UINT load_all_components( MSIPACKAGE *package )
1163{
1164 static const WCHAR query[] = {
1165 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1166 '`','C','o','m','p','o','n','e','n','t','`',0 };
1167 MSIQUERY *view;
1168 UINT r;
1169
1170 if (!list_empty(&package->components))
1171 return ERROR_SUCCESS;
1172
1173 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1174 if (r != ERROR_SUCCESS)
1175 return r;
1176
1177 r = MSI_IterateRecords(view, NULL, load_component, package);
1178 msiobj_release(&view->hdr);
1179 return r;
Aric Stewartbdb29552004-07-04 00:32:48 +00001180}
1181
Aric Stewart04598242005-06-23 16:43:24 +00001182typedef struct {
1183 MSIPACKAGE *package;
Mike McCormack1da28582005-08-22 14:09:17 +00001184 MSIFEATURE *feature;
Aric Stewart04598242005-06-23 16:43:24 +00001185} _ilfs;
1186
Mike McCormack38d67a42005-08-22 09:15:23 +00001187static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001188{
1189 ComponentList *cl;
1190
Mike McCormackee034ba2005-09-20 11:59:14 +00001191 cl = msi_alloc( sizeof (*cl) );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001192 if ( !cl )
1193 return ERROR_NOT_ENOUGH_MEMORY;
Mike McCormack38d67a42005-08-22 09:15:23 +00001194 cl->component = comp;
Mike McCormack1da28582005-08-22 14:09:17 +00001195 list_add_tail( &feature->Components, &cl->entry );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001196
1197 return ERROR_SUCCESS;
1198}
1199
James Hawkins545d0e72006-09-20 19:59:19 -07001200static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1201{
1202 FeatureList *fl;
1203
1204 fl = msi_alloc( sizeof(*fl) );
1205 if ( !fl )
1206 return ERROR_NOT_ENOUGH_MEMORY;
1207 fl->feature = child;
1208 list_add_tail( &parent->Children, &fl->entry );
1209
1210 return ERROR_SUCCESS;
1211}
1212
Aric Stewart04598242005-06-23 16:43:24 +00001213static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1214{
1215 _ilfs* ilfs= (_ilfs*)param;
1216 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00001217 MSICOMPONENT *comp;
Aric Stewart04598242005-06-23 16:43:24 +00001218
1219 component = MSI_RecordGetString(row,1);
1220
1221 /* check to see if the component is already loaded */
Mike McCormack38d67a42005-08-22 09:15:23 +00001222 comp = get_loaded_component( ilfs->package, component );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001223 if (!comp)
Aric Stewart04598242005-06-23 16:43:24 +00001224 {
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001225 ERR("unknown component %s\n", debugstr_w(component));
1226 return ERROR_FUNCTION_FAILED;
Aric Stewart04598242005-06-23 16:43:24 +00001227 }
1228
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001229 add_feature_component( ilfs->feature, comp );
1230 comp->Enabled = TRUE;
Aric Stewart04598242005-06-23 16:43:24 +00001231
1232 return ERROR_SUCCESS;
1233}
1234
James Hawkins545d0e72006-09-20 19:59:19 -07001235static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1236{
1237 MSIFEATURE *feature;
1238
1239 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1240 {
1241 if ( !lstrcmpW( feature->Feature, name ) )
1242 return feature;
1243 }
1244
1245 return NULL;
1246}
1247
Aric Stewart04598242005-06-23 16:43:24 +00001248static UINT load_feature(MSIRECORD * row, LPVOID param)
1249{
1250 MSIPACKAGE* package = (MSIPACKAGE*)param;
Mike McCormack1da28582005-08-22 14:09:17 +00001251 MSIFEATURE* feature;
Aric Stewart8e233e92005-03-01 11:45:19 +00001252 static const WCHAR Query1[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001253 {'S','E','L','E','C','T',' ',
1254 '`','C','o','m','p','o','n','e','n','t','_','`',
1255 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1256 'C','o','m','p','o','n','e','n','t','s','`',' ',
1257 'W','H','E','R','E',' ',
1258 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001259 MSIQUERY * view;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001260 UINT rc;
Aric Stewart04598242005-06-23 16:43:24 +00001261 _ilfs ilfs;
1262
Aric Stewartbdb29552004-07-04 00:32:48 +00001263 /* fill in the data */
1264
Mike McCormackee034ba2005-09-20 11:59:14 +00001265 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
Mike McCormack1da28582005-08-22 14:09:17 +00001266 if (!feature)
1267 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartbdb29552004-07-04 00:32:48 +00001268
James Hawkins545d0e72006-09-20 19:59:19 -07001269 list_init( &feature->Children );
Mike McCormack1da28582005-08-22 14:09:17 +00001270 list_init( &feature->Components );
Aric Stewartbdb29552004-07-04 00:32:48 +00001271
Mike McCormack51c66182005-10-27 12:36:12 +00001272 feature->Feature = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001273
Mike McCormack1da28582005-08-22 14:09:17 +00001274 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
Aric Stewartbdb29552004-07-04 00:32:48 +00001275
Mike McCormack51c66182005-10-27 12:36:12 +00001276 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1277 feature->Title = msi_dup_record_field( row, 3 );
1278 feature->Description = msi_dup_record_field( row, 4 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001279
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001280 if (!MSI_RecordIsNull(row,5))
Mike McCormack1da28582005-08-22 14:09:17 +00001281 feature->Display = MSI_RecordGetInteger(row,5);
Aric Stewartbdb29552004-07-04 00:32:48 +00001282
Mike McCormack1da28582005-08-22 14:09:17 +00001283 feature->Level= MSI_RecordGetInteger(row,6);
Mike McCormack51c66182005-10-27 12:36:12 +00001284 feature->Directory = msi_dup_record_field( row, 7 );
Mike McCormack1da28582005-08-22 14:09:17 +00001285 feature->Attributes = MSI_RecordGetInteger(row,8);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001286
James Hawkinsca5c1102006-09-20 19:53:56 -07001287 feature->Installed = INSTALLSTATE_UNKNOWN;
Mike McCormack575cc672006-10-26 14:09:29 +09001288 msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
Mike McCormack1da28582005-08-22 14:09:17 +00001289
1290 list_add_tail( &package->features, &feature->entry );
Aric Stewartbdb29552004-07-04 00:32:48 +00001291
1292 /* load feature components */
1293
Mike McCormack1da28582005-08-22 14:09:17 +00001294 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001295 if (rc != ERROR_SUCCESS)
Aric Stewart04598242005-06-23 16:43:24 +00001296 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001297
Mike McCormack1da28582005-08-22 14:09:17 +00001298 ilfs.package = package;
1299 ilfs.feature = feature;
1300
Aric Stewart04598242005-06-23 16:43:24 +00001301 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001302 msiobj_release(&view->hdr);
Aric Stewart04598242005-06-23 16:43:24 +00001303
1304 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001305}
1306
James Hawkins545d0e72006-09-20 19:59:19 -07001307static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1308{
1309 MSIPACKAGE* package = (MSIPACKAGE*)param;
1310 MSIFEATURE *parent, *child;
1311
1312 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1313 if (!child)
1314 return ERROR_FUNCTION_FAILED;
1315
1316 if (!child->Feature_Parent)
1317 return ERROR_SUCCESS;
1318
1319 parent = find_feature_by_name( package, child->Feature_Parent );
1320 if (!parent)
1321 return ERROR_FUNCTION_FAILED;
1322
1323 add_feature_child( parent, child );
1324 return ERROR_SUCCESS;
1325}
1326
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001327static UINT load_all_features( MSIPACKAGE *package )
1328{
1329 static const WCHAR query[] = {
1330 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1331 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1332 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1333 MSIQUERY *view;
1334 UINT r;
1335
1336 if (!list_empty(&package->features))
1337 return ERROR_SUCCESS;
1338
1339 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1340 if (r != ERROR_SUCCESS)
1341 return r;
1342
1343 r = MSI_IterateRecords( view, NULL, load_feature, package );
James Hawkins545d0e72006-09-20 19:59:19 -07001344 if (r != ERROR_SUCCESS)
1345 return r;
1346
1347 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001348 msiobj_release( &view->hdr );
James Hawkins545d0e72006-09-20 19:59:19 -07001349
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001350 return r;
1351}
1352
Mike McCormackc1513be2006-03-21 19:40:36 +09001353static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1354{
1355 if (!p)
1356 return p;
1357 p = strchrW(p, ch);
1358 if (!p)
1359 return p;
1360 *p = 0;
1361 return p+1;
1362}
1363
Aric Stewart04598242005-06-23 16:43:24 +00001364static UINT load_file(MSIRECORD *row, LPVOID param)
Aric Stewartc5a14432005-05-18 17:46:12 +00001365{
Aric Stewart04598242005-06-23 16:43:24 +00001366 MSIPACKAGE* package = (MSIPACKAGE*)param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00001367 LPCWSTR component;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001368 MSIFILE *file;
Aric Stewartc5a14432005-05-18 17:46:12 +00001369
1370 /* fill in the data */
1371
Mike McCormackee034ba2005-09-20 11:59:14 +00001372 file = msi_alloc_zero( sizeof (MSIFILE) );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001373 if (!file)
1374 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartc5a14432005-05-18 17:46:12 +00001375
Mike McCormack51c66182005-10-27 12:36:12 +00001376 file->File = msi_dup_record_field( row, 1 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001377
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001378 component = MSI_RecordGetString( row, 2 );
1379 file->Component = get_loaded_component( package, component );
Aric Stewart09b0aba2005-06-09 20:30:59 +00001380
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001381 if (!file->Component)
Aric Stewart09b0aba2005-06-09 20:30:59 +00001382 ERR("Unfound Component %s\n",debugstr_w(component));
Aric Stewartc5a14432005-05-18 17:46:12 +00001383
Mike McCormack51c66182005-10-27 12:36:12 +00001384 file->FileName = msi_dup_record_field( row, 3 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001385 reduce_to_longfilename( file->FileName );
Aric Stewartc5a14432005-05-18 17:46:12 +00001386
Mike McCormack51c66182005-10-27 12:36:12 +00001387 file->ShortName = msi_dup_record_field( row, 3 );
Mike McCormackc1513be2006-03-21 19:40:36 +09001388 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
Aric Stewartc5a14432005-05-18 17:46:12 +00001389
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001390 file->FileSize = MSI_RecordGetInteger( row, 4 );
Mike McCormack51c66182005-10-27 12:36:12 +00001391 file->Version = msi_dup_record_field( row, 5 );
1392 file->Language = msi_dup_record_field( row, 6 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001393 file->Attributes = MSI_RecordGetInteger( row, 7 );
1394 file->Sequence = MSI_RecordGetInteger( row, 8 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001395
Mike McCormackdded8fb2005-11-02 10:56:42 +00001396 file->state = msifs_invalid;
Aric Stewartc5a14432005-05-18 17:46:12 +00001397
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001398 /* if the compressed bits are not set in the file attributes,
1399 * then read the information from the package word count property
1400 */
James Hawkins98d14862006-07-31 11:15:52 -07001401 if (file->Attributes & msidbFileAttributesCompressed)
1402 {
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001403 file->IsCompressed = TRUE;
1404 }
1405 else if (file->Attributes & msidbFileAttributesNoncompressed)
1406 {
1407 file->IsCompressed = FALSE;
1408 }
1409 else
1410 {
1411 file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1412 }
1413
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001414 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1415
1416 list_add_tail( &package->files, &file->entry );
Aric Stewartc5a14432005-05-18 17:46:12 +00001417
1418 return ERROR_SUCCESS;
1419}
1420
1421static UINT load_all_files(MSIPACKAGE *package)
1422{
1423 MSIQUERY * view;
Aric Stewartc5a14432005-05-18 17:46:12 +00001424 UINT rc;
1425 static const WCHAR Query[] =
1426 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001427 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1428 '`','S','e','q','u','e','n','c','e','`', 0};
Aric Stewartc5a14432005-05-18 17:46:12 +00001429
Mike McCormack9a9195d2006-07-19 17:01:07 +09001430 if (!list_empty(&package->files))
1431 return ERROR_SUCCESS;
1432
Aric Stewartc5a14432005-05-18 17:46:12 +00001433 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1434 if (rc != ERROR_SUCCESS)
1435 return ERROR_SUCCESS;
Aric Stewartc5a14432005-05-18 17:46:12 +00001436
Aric Stewart04598242005-06-23 16:43:24 +00001437 rc = MSI_IterateRecords(view, NULL, load_file, package);
Aric Stewartc5a14432005-05-18 17:46:12 +00001438 msiobj_release(&view->hdr);
1439
1440 return ERROR_SUCCESS;
1441}
1442
Mike McCormack7eb27022006-11-22 15:13:12 +09001443static UINT load_folder( MSIRECORD *row, LPVOID param )
1444{
1445 MSIPACKAGE *package = param;
1446 static const WCHAR szDot[] = { '.',0 };
1447 static WCHAR szEmpty[] = { 0 };
1448 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1449 MSIFOLDER *folder;
1450
1451 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1452 if (!folder)
1453 return ERROR_NOT_ENOUGH_MEMORY;
1454
1455 folder->Directory = msi_dup_record_field( row, 1 );
1456
1457 TRACE("%s\n", debugstr_w(folder->Directory));
1458
1459 p = msi_dup_record_field(row, 3);
1460
1461 /* split src and target dir */
1462 tgt_short = p;
1463 src_short = folder_split_path( p, ':' );
1464
1465 /* split the long and short paths */
1466 tgt_long = folder_split_path( tgt_short, '|' );
1467 src_long = folder_split_path( src_short, '|' );
1468
1469 /* check for no-op dirs */
1470 if (!lstrcmpW(szDot, tgt_short))
1471 tgt_short = szEmpty;
1472 if (!lstrcmpW(szDot, src_short))
1473 src_short = szEmpty;
1474
1475 if (!tgt_long)
1476 tgt_long = tgt_short;
1477
1478 if (!src_short) {
1479 src_short = tgt_short;
1480 src_long = tgt_long;
1481 }
1482
1483 if (!src_long)
1484 src_long = src_short;
1485
1486 /* FIXME: use the target short path too */
1487 folder->TargetDefault = strdupW(tgt_long);
1488 folder->SourceShortPath = strdupW(src_short);
1489 folder->SourceLongPath = strdupW(src_long);
1490 msi_free(p);
1491
1492 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1493 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1494 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1495
1496 folder->Parent = msi_dup_record_field( row, 2 );
1497
1498 folder->Property = msi_dup_property( package, folder->Directory );
1499
1500 list_add_tail( &package->folders, &folder->entry );
1501
1502 TRACE("returning %p\n", folder);
1503
1504 return ERROR_SUCCESS;
1505}
1506
1507static UINT load_all_folders( MSIPACKAGE *package )
1508{
1509 static const WCHAR query[] = {
1510 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1511 '`','D','i','r','e','c','t','o','r','y','`',0 };
1512 MSIQUERY *view;
1513 UINT r;
1514
1515 if (!list_empty(&package->folders))
1516 return ERROR_SUCCESS;
1517
1518 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1519 if (r != ERROR_SUCCESS)
1520 return r;
1521
1522 r = MSI_IterateRecords(view, NULL, load_folder, package);
1523 msiobj_release(&view->hdr);
1524 return r;
1525}
Aric Stewartc5a14432005-05-18 17:46:12 +00001526
Aric Stewartbdb29552004-07-04 00:32:48 +00001527/*
Mike McCormack9a9195d2006-07-19 17:01:07 +09001528 * I am not doing any of the costing functionality yet.
Aric Stewartbdb29552004-07-04 00:32:48 +00001529 * Mostly looking at doing the Component and Feature loading
1530 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001531 * The native MSI does A LOT of modification to tables here. Mostly adding
Mike McCormack9a9195d2006-07-19 17:01:07 +09001532 * a lot of temporary columns to the Feature and Component tables.
Aric Stewartbdb29552004-07-04 00:32:48 +00001533 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001534 * note: Native msi also tracks the short filename. But I am only going to
Aric Stewartbdb29552004-07-04 00:32:48 +00001535 * track the long ones. Also looking at this directory table
1536 * it appears that the directory table does not get the parents
Mike McCormack9a9195d2006-07-19 17:01:07 +09001537 * resolved base on property only based on their entries in the
Aric Stewartbdb29552004-07-04 00:32:48 +00001538 * directory table.
1539 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001540static UINT ACTION_CostInitialize(MSIPACKAGE *package)
Aric Stewartbdb29552004-07-04 00:32:48 +00001541{
Aric Stewart8e233e92005-03-01 11:45:19 +00001542 static const WCHAR szCosting[] =
1543 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001544 static const WCHAR szZero[] = { '0', 0 };
Aric Stewartbdb29552004-07-04 00:32:48 +00001545
Mike McCormack9293f862005-10-30 19:16:45 +00001546 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00001547 return ERROR_SUCCESS;
Mike McCormack9a9195d2006-07-19 17:01:07 +09001548
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001549 MSI_SetPropertyW(package, szCosting, szZero);
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001550 MSI_SetPropertyW(package, cszRootDrive, c_colon);
Aric Stewartbdb29552004-07-04 00:32:48 +00001551
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001552 load_all_components( package );
1553 load_all_features( package );
1554 load_all_files( package );
Mike McCormack7eb27022006-11-22 15:13:12 +09001555 load_all_folders( package );
Aric Stewartec688fb2004-07-04 00:35:52 +00001556
Aric Stewartec688fb2004-07-04 00:35:52 +00001557 return ERROR_SUCCESS;
1558}
1559
Mike McCormackf9acfe62005-06-07 20:29:51 +00001560static UINT execute_script(MSIPACKAGE *package, UINT script )
Aric Stewart9cd707d2005-05-27 19:24:22 +00001561{
1562 int i;
1563 UINT rc = ERROR_SUCCESS;
1564
1565 TRACE("Executing Script %i\n",script);
1566
Mike McCormackaa81e4f2006-01-10 12:09:19 +01001567 if (!package->script)
1568 {
1569 ERR("no script!\n");
1570 return ERROR_FUNCTION_FAILED;
1571 }
1572
Aric Stewart9cd707d2005-05-27 19:24:22 +00001573 for (i = 0; i < package->script->ActionCount[script]; i++)
1574 {
1575 LPWSTR action;
1576 action = package->script->Actions[script][i];
1577 ui_actionstart(package, action);
1578 TRACE("Executing Action (%s)\n",debugstr_w(action));
1579 rc = ACTION_PerformAction(package, action, TRUE);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001580 if (rc != ERROR_SUCCESS)
1581 break;
1582 }
Mike McCormackf86cfd42006-11-02 18:12:43 +09001583 msi_free_action_script(package, script);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001584 return rc;
1585}
1586
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001587static UINT ACTION_FileCost(MSIPACKAGE *package)
Aric Stewartec688fb2004-07-04 00:35:52 +00001588{
Aric Stewartbdb29552004-07-04 00:32:48 +00001589 return ERROR_SUCCESS;
1590}
1591
Mike McCormackb7669152006-10-30 16:35:09 +09001592static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001593{
Mike McCormack38d67a42005-08-22 09:15:23 +00001594 MSICOMPONENT *comp;
Aric Stewart78a04e32005-02-22 15:47:00 +00001595
Mike McCormack38d67a42005-08-22 09:15:23 +00001596 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001597 {
1598 INSTALLSTATE res;
James Hawkins32f57022006-09-20 19:57:03 -07001599
1600 if (!comp->ComponentId)
1601 continue;
1602
Mike McCormackb7669152006-10-30 16:35:09 +09001603 res = MsiGetComponentPathW( package->ProductCode,
Mike McCormack38d67a42005-08-22 09:15:23 +00001604 comp->ComponentId, NULL, NULL);
Aric Stewart78a04e32005-02-22 15:47:00 +00001605 if (res < 0)
1606 res = INSTALLSTATE_ABSENT;
Mike McCormack38d67a42005-08-22 09:15:23 +00001607 comp->Installed = res;
Aric Stewart78a04e32005-02-22 15:47:00 +00001608 }
Mike McCormackb7669152006-10-30 16:35:09 +09001609}
1610
1611/* scan for and update current install states */
1612static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
1613{
1614 MSICOMPONENT *comp;
1615 MSIFEATURE *feature;
Aric Stewart78a04e32005-02-22 15:47:00 +00001616
Mike McCormack1da28582005-08-22 14:09:17 +00001617 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001618 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001619 ComponentList *cl;
James Hawkins545d0e72006-09-20 19:59:19 -07001620 INSTALLSTATE res = INSTALLSTATE_ABSENT;
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001621
Mike McCormack1da28582005-08-22 14:09:17 +00001622 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001623 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001624 comp= cl->component;
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001625
James Hawkins32f57022006-09-20 19:57:03 -07001626 if (!comp->ComponentId)
1627 {
1628 res = INSTALLSTATE_ABSENT;
1629 break;
1630 }
1631
James Hawkins545d0e72006-09-20 19:59:19 -07001632 if (res == INSTALLSTATE_ABSENT)
Mike McCormack38d67a42005-08-22 09:15:23 +00001633 res = comp->Installed;
Aric Stewart78a04e32005-02-22 15:47:00 +00001634 else
1635 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001636 if (res == comp->Installed)
Aric Stewart78a04e32005-02-22 15:47:00 +00001637 continue;
1638
Paul Vriensded99432006-11-12 12:01:26 +01001639 if (res != INSTALLSTATE_DEFAULT && res != INSTALLSTATE_LOCAL &&
James Hawkins32f57022006-09-20 19:57:03 -07001640 res != INSTALLSTATE_SOURCE)
1641 {
1642 res = INSTALLSTATE_INCOMPLETE;
1643 }
Aric Stewart78a04e32005-02-22 15:47:00 +00001644 }
1645 }
Mike McCormack8aa1a912005-08-25 19:19:10 +00001646 feature->Installed = res;
Aric Stewart78a04e32005-02-22 15:47:00 +00001647 }
1648}
1649
Aric Stewart78a04e32005-02-22 15:47:00 +00001650static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
1651 INSTALLSTATE state)
Aric Stewartae1aa322004-12-27 19:02:59 +00001652{
Aric Stewartae1aa322004-12-27 19:02:59 +00001653 static const WCHAR all[]={'A','L','L',0};
Mike McCormack72faac02005-09-08 11:03:35 +00001654 LPWSTR override;
Mike McCormack1da28582005-08-22 14:09:17 +00001655 MSIFEATURE *feature;
Aric Stewartae1aa322004-12-27 19:02:59 +00001656
Mike McCormack062ad502005-09-15 15:04:08 +00001657 override = msi_dup_property( package, property );
Mike McCormack72faac02005-09-08 11:03:35 +00001658 if (!override)
1659 return FALSE;
Mike McCormack575cc672006-10-26 14:09:29 +09001660
Mike McCormack72faac02005-09-08 11:03:35 +00001661 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001662 {
Mike McCormack72faac02005-09-08 11:03:35 +00001663 if (strcmpiW(override,all)==0)
Mike McCormack575cc672006-10-26 14:09:29 +09001664 msi_feature_set_state( feature, state );
Mike McCormack72faac02005-09-08 11:03:35 +00001665 else
1666 {
1667 LPWSTR ptr = override;
1668 LPWSTR ptr2 = strchrW(override,',');
Aric Stewartd900b532004-12-27 19:12:35 +00001669
Mike McCormack72faac02005-09-08 11:03:35 +00001670 while (ptr)
1671 {
1672 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1673 || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
Aric Stewartd900b532004-12-27 19:12:35 +00001674 {
Mike McCormack575cc672006-10-26 14:09:29 +09001675 msi_feature_set_state( feature, state );
Mike McCormack72faac02005-09-08 11:03:35 +00001676 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001677 }
Mike McCormack72faac02005-09-08 11:03:35 +00001678 if (ptr2)
1679 {
1680 ptr=ptr2+1;
1681 ptr2 = strchrW(ptr,',');
1682 }
1683 else
1684 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001685 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001686 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001687 }
Mike McCormackee034ba2005-09-20 11:59:14 +00001688 msi_free(override);
Aric Stewart78a04e32005-02-22 15:47:00 +00001689
Mike McCormack72faac02005-09-08 11:03:35 +00001690 return TRUE;
Aric Stewart78a04e32005-02-22 15:47:00 +00001691}
1692
James Hawkins7bcac312006-07-19 11:17:16 -07001693UINT MSI_SetFeatureStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001694{
Mike McCormack74f0de92005-09-29 10:32:39 +00001695 int install_level;
Aric Stewart8e233e92005-03-01 11:45:19 +00001696 static const WCHAR szlevel[] =
1697 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1698 static const WCHAR szAddLocal[] =
1699 {'A','D','D','L','O','C','A','L',0};
1700 static const WCHAR szRemove[] =
1701 {'R','E','M','O','V','E',0};
Aric Stewartd5655f92005-11-02 14:21:17 +00001702 static const WCHAR szReinstall[] =
1703 {'R','E','I','N','S','T','A','L','L',0};
Aric Stewart78a04e32005-02-22 15:47:00 +00001704 BOOL override = FALSE;
Mike McCormack38d67a42005-08-22 09:15:23 +00001705 MSICOMPONENT* component;
Mike McCormack1da28582005-08-22 14:09:17 +00001706 MSIFEATURE *feature;
1707
Aric Stewart78a04e32005-02-22 15:47:00 +00001708
1709 /* I do not know if this is where it should happen.. but */
1710
1711 TRACE("Checking Install Level\n");
1712
Mike McCormack74f0de92005-09-29 10:32:39 +00001713 install_level = msi_get_property_int( package, szlevel, 1 );
Aric Stewart78a04e32005-02-22 15:47:00 +00001714
Francois Gouget58162f82006-10-13 02:19:42 +02001715 /* ok here is the _real_ rub
Francois Gougetfbb33432005-03-02 13:53:50 +00001716 * all these activation/deactivation things happen in order and things
1717 * later on the list override things earlier on the list.
Aric Stewart78a04e32005-02-22 15:47:00 +00001718 * 1) INSTALLLEVEL processing
1719 * 2) ADDLOCAL
1720 * 3) REMOVE
1721 * 4) ADDSOURCE
1722 * 5) ADDDEFAULT
1723 * 6) REINSTALL
1724 * 7) COMPADDLOCAL
1725 * 8) COMPADDSOURCE
1726 * 9) FILEADDLOCAL
1727 * 10) FILEADDSOURCE
1728 * 11) FILEADDDEFAULT
Francois Gougetfbb33432005-03-02 13:53:50 +00001729 * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1730 * ignored for all the features. seems strange, especially since it is not
Mike McCormack6395ff62006-10-26 12:34:52 +09001731 * documented anywhere, but it is how it works.
Aric Stewart78a04e32005-02-22 15:47:00 +00001732 *
Francois Gougetfbb33432005-03-02 13:53:50 +00001733 * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1734 * REMOVE are the big ones, since we don't handle administrative installs
1735 * yet anyway.
Aric Stewart78a04e32005-02-22 15:47:00 +00001736 */
1737 override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1738 override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
Aric Stewartd5655f92005-11-02 14:21:17 +00001739 override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
Aric Stewart78a04e32005-02-22 15:47:00 +00001740
1741 if (!override)
Aric Stewartfbdd7092004-12-27 19:06:22 +00001742 {
Mike McCormack1da28582005-08-22 14:09:17 +00001743 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001744 {
Mike McCormack1da28582005-08-22 14:09:17 +00001745 BOOL feature_state = ((feature->Level > 0) &&
1746 (feature->Level <= install_level));
Aric Stewartae1aa322004-12-27 19:02:59 +00001747
Mike McCormack1da28582005-08-22 14:09:17 +00001748 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001749 {
Mike McCormack1da28582005-08-22 14:09:17 +00001750 if (feature->Attributes & msidbFeatureAttributesFavorSource)
Mike McCormack6395ff62006-10-26 12:34:52 +09001751 msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
Mike McCormack1da28582005-08-22 14:09:17 +00001752 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
Mike McCormack6395ff62006-10-26 12:34:52 +09001753 msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
Aric Stewartb39d8fc2005-05-13 13:56:39 +00001754 else
Mike McCormack6395ff62006-10-26 12:34:52 +09001755 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
Aric Stewartfbdd7092004-12-27 19:06:22 +00001756 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001757 }
James Hawkins545d0e72006-09-20 19:59:19 -07001758
1759 /* disable child features of unselected parent features */
1760 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1761 {
1762 FeatureList *fl;
1763
1764 if (feature->Level > 0 && feature->Level <= install_level)
1765 continue;
1766
1767 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
Mike McCormack6395ff62006-10-26 12:34:52 +09001768 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
James Hawkins545d0e72006-09-20 19:59:19 -07001769 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001770 }
Aric Stewart6999a042005-06-08 19:20:02 +00001771 else
1772 {
1773 /* set the Preselected Property */
1774 static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1775 static const WCHAR szOne[] = { '1', 0 };
1776
1777 MSI_SetPropertyW(package,szPreselected,szOne);
1778 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001779
Aric Stewartfbdd7092004-12-27 19:06:22 +00001780 /*
Mike McCormack6395ff62006-10-26 12:34:52 +09001781 * now we want to enable or disable components base on feature
1782 */
Aric Stewartfbdd7092004-12-27 19:06:22 +00001783
Mike McCormack1da28582005-08-22 14:09:17 +00001784 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001785 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001786 ComponentList *cl;
1787
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001788 TRACE("Examining Feature %s (Installed %i, Action %i)\n",
Mike McCormack97419ae2006-12-05 18:24:39 +09001789 debugstr_w(feature->Feature), feature->Installed, feature->Action);
1790
1791 /* features with components that have compressed files are made local */
1792 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1793 {
1794 if (cl->component->Enabled &&
1795 cl->component->ForceLocalState &&
1796 feature->Action == INSTALLSTATE_SOURCE)
1797 {
1798 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1799 break;
1800 }
1801 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001802
Mike McCormack1da28582005-08-22 14:09:17 +00001803 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001804 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001805 component = cl->component;
Aric Stewartfbdd7092004-12-27 19:06:22 +00001806
Mike McCormack87fa8542006-11-10 15:38:51 +09001807 if (!component->Enabled)
1808 continue;
1809
Mike McCormack97419ae2006-12-05 18:24:39 +09001810 switch (feature->Action)
Mike McCormackad80ece2006-11-10 15:38:31 +09001811 {
Mike McCormack97419ae2006-12-05 18:24:39 +09001812 case INSTALLSTATE_ADVERTISED:
1813 component->hasAdvertiseFeature = 1;
1814 break;
1815 case INSTALLSTATE_SOURCE:
1816 component->hasSourceFeature = 1;
1817 break;
1818 case INSTALLSTATE_LOCAL:
1819 component->hasLocalFeature = 1;
1820 break;
1821 case INSTALLSTATE_DEFAULT:
1822 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1823 component->hasAdvertiseFeature = 1;
1824 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1825 component->hasSourceFeature = 1;
Mike McCormackad80ece2006-11-10 15:38:31 +09001826 else
Mike McCormack97419ae2006-12-05 18:24:39 +09001827 component->hasLocalFeature = 1;
1828 break;
1829 default:
1830 break;
James Hawkins929395c2006-10-19 15:51:33 -07001831 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001832 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001833 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001834
Mike McCormack38d67a42005-08-22 09:15:23 +00001835 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001836 {
Mike McCormack97419ae2006-12-05 18:24:39 +09001837 /* if the component isn't enabled, leave it alone */
1838 if (!component->Enabled)
1839 continue;
1840
1841 /* check if it's local or source */
1842 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1843 (component->hasLocalFeature || component->hasSourceFeature))
1844 {
1845 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1846 !component->ForceLocalState)
1847 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1848 else
1849 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1850 continue;
1851 }
1852
1853 /* if any feature is local, the component must be local too */
1854 if (component->hasLocalFeature)
1855 {
1856 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1857 continue;
1858 }
1859
1860 if (component->hasSourceFeature)
1861 {
1862 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1863 continue;
1864 }
1865
1866 if (component->hasAdvertiseFeature)
1867 {
1868 msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1869 continue;
1870 }
1871
1872 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1873 }
1874
1875 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1876 {
Mike McCormack9efb7b72006-11-07 17:55:43 +09001877 if (component->Action == INSTALLSTATE_DEFAULT)
1878 {
1879 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1880 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1881 }
1882
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001883 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1884 debugstr_w(component->Component), component->Installed, component->Action);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001885 }
1886
1887
Aric Stewartae1aa322004-12-27 19:02:59 +00001888 return ERROR_SUCCESS;
1889}
1890
Aric Stewart443ad4d2005-06-21 20:50:12 +00001891static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1892{
1893 MSIPACKAGE *package = (MSIPACKAGE*)param;
1894 LPCWSTR name;
1895 LPWSTR path;
1896
1897 name = MSI_RecordGetString(row,1);
1898
1899 /* This helper function now does ALL the work */
1900 TRACE("Dir %s ...\n",debugstr_w(name));
Aric Stewart443ad4d2005-06-21 20:50:12 +00001901 path = resolve_folder(package,name,FALSE,TRUE,NULL);
1902 TRACE("resolves to %s\n",debugstr_w(path));
Mike McCormackee034ba2005-09-20 11:59:14 +00001903 msi_free(path);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001904
1905 return ERROR_SUCCESS;
1906}
1907
1908static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1909{
1910 MSIPACKAGE *package = (MSIPACKAGE*)param;
Mike McCormack1da28582005-08-22 14:09:17 +00001911 LPCWSTR name;
1912 MSIFEATURE *feature;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001913
Mike McCormack1da28582005-08-22 14:09:17 +00001914 name = MSI_RecordGetString( row, 1 );
Aric Stewart443ad4d2005-06-21 20:50:12 +00001915
Mike McCormack1da28582005-08-22 14:09:17 +00001916 feature = get_loaded_feature( package, name );
1917 if (!feature)
1918 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
Aric Stewart443ad4d2005-06-21 20:50:12 +00001919 else
1920 {
1921 LPCWSTR Condition;
1922 Condition = MSI_RecordGetString(row,3);
1923
Aric Stewart0713f092005-06-24 11:51:29 +00001924 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
Aric Stewart443ad4d2005-06-21 20:50:12 +00001925 {
1926 int level = MSI_RecordGetInteger(row,2);
Mike McCormack1da28582005-08-22 14:09:17 +00001927 TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1928 feature->Level = level;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001929 }
1930 }
1931 return ERROR_SUCCESS;
1932}
1933
Mike McCormackd1723de2006-10-24 17:37:26 +09001934LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1935{
1936 static const WCHAR name_fmt[] =
1937 {'%','u','.','%','u','.','%','u','.','%','u',0};
1938 static WCHAR name[] = {'\\',0};
1939 VS_FIXEDFILEINFO *lpVer;
1940 WCHAR filever[0x100];
1941 LPVOID version;
1942 DWORD versize;
1943 DWORD handle;
1944 UINT sz;
1945
1946 TRACE("%s\n", debugstr_w(filename));
1947
1948 versize = GetFileVersionInfoSizeW( filename, &handle );
1949 if (!versize)
1950 return NULL;
1951
1952 version = msi_alloc( versize );
1953 GetFileVersionInfoW( filename, 0, versize, version );
1954
1955 VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1956 msi_free( version );
1957
1958 sprintfW( filever, name_fmt,
1959 HIWORD(lpVer->dwFileVersionMS),
1960 LOWORD(lpVer->dwFileVersionMS),
1961 HIWORD(lpVer->dwFileVersionLS),
1962 LOWORD(lpVer->dwFileVersionLS));
1963
1964 return strdupW( filever );
1965}
1966
Mike McCormackc5c55212006-11-07 15:05:48 +09001967static UINT msi_check_file_install_states( MSIPACKAGE *package )
Aric Stewart401bd3f2004-06-28 20:34:35 +00001968{
Mike McCormackc5c55212006-11-07 15:05:48 +09001969 LPWSTR file_version;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001970 MSIFILE *file;
Aric Stewartec688fb2004-07-04 00:35:52 +00001971
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001972 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartec688fb2004-07-04 00:35:52 +00001973 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00001974 MSICOMPONENT* comp = file->Component;
1975 LPWSTR p;
Aric Stewartec688fb2004-07-04 00:35:52 +00001976
Mike McCormackf11c8b02005-09-09 14:48:51 +00001977 if (!comp)
1978 continue;
Aric Stewartec688fb2004-07-04 00:35:52 +00001979
James Hawkinsd893cb72006-09-20 19:55:01 -07001980 if (file->IsCompressed)
James Hawkinsd893cb72006-09-20 19:55:01 -07001981 comp->ForceLocalState = TRUE;
James Hawkinsd893cb72006-09-20 19:55:01 -07001982
Mike McCormackf11c8b02005-09-09 14:48:51 +00001983 /* calculate target */
1984 p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1985
Mike McCormackee034ba2005-09-20 11:59:14 +00001986 msi_free(file->TargetPath);
Mike McCormackf11c8b02005-09-09 14:48:51 +00001987
1988 TRACE("file %s is named %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09001989 debugstr_w(file->File), debugstr_w(file->FileName));
Mike McCormackf11c8b02005-09-09 14:48:51 +00001990
1991 file->TargetPath = build_directory_name(2, p, file->FileName);
1992
Mike McCormackee034ba2005-09-20 11:59:14 +00001993 msi_free(p);
Mike McCormackf11c8b02005-09-09 14:48:51 +00001994
1995 TRACE("file %s resolves to %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09001996 debugstr_w(file->File), debugstr_w(file->TargetPath));
Mike McCormackf11c8b02005-09-09 14:48:51 +00001997
Mike McCormackddf0b592006-10-31 14:32:48 +09001998 /* don't check files of components that aren't installed */
1999 if (comp->Installed == INSTALLSTATE_UNKNOWN ||
2000 comp->Installed == INSTALLSTATE_ABSENT)
2001 {
2002 file->state = msifs_missing; /* assume files are missing */
2003 continue;
2004 }
2005
Mike McCormackf11c8b02005-09-09 14:48:51 +00002006 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
Aric Stewartec688fb2004-07-04 00:35:52 +00002007 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002008 file->state = msifs_missing;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002009 comp->Cost += file->FileSize;
Mike McCormackddf0b592006-10-31 14:32:48 +09002010 comp->Installed = INSTALLSTATE_INCOMPLETE;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002011 continue;
2012 }
Mike McCormackba8200b2004-12-22 15:25:30 +00002013
Mike McCormackd1723de2006-10-24 17:37:26 +09002014 if (file->Version &&
2015 (file_version = msi_get_disk_file_version( file->TargetPath )))
Mike McCormackf11c8b02005-09-09 14:48:51 +00002016 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00002017 TRACE("new %s old %s\n", debugstr_w(file->Version),
Mike McCormackd1723de2006-10-24 17:37:26 +09002018 debugstr_w(file_version));
2019 /* FIXME: seems like a bad way to compare version numbers */
2020 if (lstrcmpiW(file_version, file->Version)<0)
Aric Stewartec688fb2004-07-04 00:35:52 +00002021 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002022 file->state = msifs_overwrite;
Aric Stewartec688fb2004-07-04 00:35:52 +00002023 comp->Cost += file->FileSize;
Mike McCormackddf0b592006-10-31 14:32:48 +09002024 comp->Installed = INSTALLSTATE_INCOMPLETE;
Aric Stewartec688fb2004-07-04 00:35:52 +00002025 }
2026 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002027 file->state = msifs_present;
Mike McCormackd1723de2006-10-24 17:37:26 +09002028 msi_free( file_version );
Mike McCormackf11c8b02005-09-09 14:48:51 +00002029 }
2030 else
Mike McCormackdded8fb2005-11-02 10:56:42 +00002031 file->state = msifs_present;
Aric Stewartec688fb2004-07-04 00:35:52 +00002032 }
2033
Mike McCormackc5c55212006-11-07 15:05:48 +09002034 return ERROR_SUCCESS;
2035}
2036
2037/*
2038 * A lot is done in this function aside from just the costing.
2039 * The costing needs to be implemented at some point but for now I am going
2040 * to focus on the directory building
2041 *
2042 */
2043static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2044{
2045 static const WCHAR ExecSeqQuery[] =
2046 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2047 '`','D','i','r','e','c','t','o','r','y','`',0};
2048 static const WCHAR ConditionQuery[] =
2049 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2050 '`','C','o','n','d','i','t','i','o','n','`',0};
2051 static const WCHAR szCosting[] =
2052 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2053 static const WCHAR szlevel[] =
2054 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2055 static const WCHAR szOne[] = { '1', 0 };
2056 MSICOMPONENT *comp;
2057 UINT rc;
2058 MSIQUERY * view;
2059 LPWSTR level;
2060
2061 if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
2062 return ERROR_SUCCESS;
2063
2064 TRACE("Building Directory properties\n");
2065
2066 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2067 if (rc == ERROR_SUCCESS)
2068 {
2069 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2070 package);
2071 msiobj_release(&view->hdr);
2072 }
2073
2074 /* read components states from the registry */
2075 ACTION_GetComponentInstallStates(package);
2076
2077 TRACE("File calculations\n");
2078 msi_check_file_install_states( package );
2079
Aric Stewart7d3e5972004-07-04 00:36:58 +00002080 TRACE("Evaluating Condition Table\n");
Aric Stewart2e9b5f72004-07-04 00:31:17 +00002081
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002082 rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
Aric Stewart84837d92004-07-20 01:22:37 +00002083 if (rc == ERROR_SUCCESS)
2084 {
Aric Stewart443ad4d2005-06-21 20:50:12 +00002085 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2086 package);
Mike McCormackac6a4132005-01-04 20:36:12 +00002087 msiobj_release(&view->hdr);
Aric Stewart84837d92004-07-20 01:22:37 +00002088 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002089
2090 TRACE("Enabling or Disabling Components\n");
Mike McCormack38d67a42005-08-22 09:15:23 +00002091 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewart7d3e5972004-07-04 00:36:58 +00002092 {
Mike McCormack9375fd92006-10-27 17:29:02 +09002093 if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002094 {
Mike McCormack9375fd92006-10-27 17:29:02 +09002095 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2096 comp->Enabled = FALSE;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002097 }
2098 }
2099
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002100 MSI_SetPropertyW(package,szCosting,szOne);
Aric Stewart8cc14a92004-12-27 18:56:30 +00002101 /* set default run level if not set */
Mike McCormack062ad502005-09-15 15:04:08 +00002102 level = msi_dup_property( package, szlevel );
Aric Stewart8cc14a92004-12-27 18:56:30 +00002103 if (!level)
2104 MSI_SetPropertyW(package,szlevel, szOne);
Mike McCormackee034ba2005-09-20 11:59:14 +00002105 msi_free(level);
Aric Stewartae1aa322004-12-27 19:02:59 +00002106
Mike McCormackb7669152006-10-30 16:35:09 +09002107 ACTION_UpdateFeatureInstallStates(package);
Aric Stewartae1aa322004-12-27 19:02:59 +00002108
James Hawkins7c7f0bb2006-07-19 11:15:37 -07002109 return MSI_SetFeatureStates(package);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002110}
2111
Francois Gougetda8b3dd2005-01-26 21:09:04 +00002112/* OK this value is "interpreted" and then formatted based on the
Aric Stewart6e160f12004-06-29 04:07:22 +00002113 first few characters */
Aric Stewart09b0aba2005-06-09 20:30:59 +00002114static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
Aric Stewart401bd3f2004-06-28 20:34:35 +00002115 DWORD *size)
2116{
2117 LPSTR data = NULL;
Aric Stewart6e160f12004-06-29 04:07:22 +00002118 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
Aric Stewart401bd3f2004-06-28 20:34:35 +00002119 {
Aric Stewart6e160f12004-06-29 04:07:22 +00002120 if (value[1]=='x')
2121 {
2122 LPWSTR ptr;
2123 CHAR byte[5];
Aric Stewart6186b2b2005-05-16 21:37:35 +00002124 LPWSTR deformated = NULL;
Aric Stewart6e160f12004-06-29 04:07:22 +00002125 int count;
2126
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002127 deformat_string(package, &value[2], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002128
2129 /* binary value type */
Aric Stewart6186b2b2005-05-16 21:37:35 +00002130 ptr = deformated;
2131 *type = REG_BINARY;
2132 if (strlenW(ptr)%2)
2133 *size = (strlenW(ptr)/2)+1;
2134 else
2135 *size = strlenW(ptr)/2;
2136
Mike McCormackee034ba2005-09-20 11:59:14 +00002137 data = msi_alloc(*size);
Aric Stewart6186b2b2005-05-16 21:37:35 +00002138
Aric Stewart6e160f12004-06-29 04:07:22 +00002139 byte[0] = '0';
2140 byte[1] = 'x';
2141 byte[4] = 0;
2142 count = 0;
Aric Stewart6186b2b2005-05-16 21:37:35 +00002143 /* if uneven pad with a zero in front */
2144 if (strlenW(ptr)%2)
2145 {
2146 byte[2]= '0';
2147 byte[3]= *ptr;
2148 ptr++;
2149 data[count] = (BYTE)strtol(byte,NULL,0);
2150 count ++;
2151 TRACE("Uneven byte count\n");
2152 }
Aric Stewart6e160f12004-06-29 04:07:22 +00002153 while (*ptr)
2154 {
2155 byte[2]= *ptr;
2156 ptr++;
2157 byte[3]= *ptr;
2158 ptr++;
2159 data[count] = (BYTE)strtol(byte,NULL,0);
2160 count ++;
2161 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002162 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002163
Mike McCormackf1d46462006-10-05 13:41:22 +09002164 TRACE("Data %i bytes(%i)\n",*size,count);
Aric Stewart6e160f12004-06-29 04:07:22 +00002165 }
2166 else
2167 {
2168 LPWSTR deformated;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002169 LPWSTR p;
2170 DWORD d = 0;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002171 deformat_string(package, &value[1], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002172
2173 *type=REG_DWORD;
2174 *size = sizeof(DWORD);
Mike McCormackee034ba2005-09-20 11:59:14 +00002175 data = msi_alloc(*size);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002176 p = deformated;
2177 if (*p == '-')
2178 p++;
2179 while (*p)
2180 {
2181 if ( (*p < '0') || (*p > '9') )
2182 break;
2183 d *= 10;
2184 d += (*p - '0');
2185 p++;
2186 }
2187 if (deformated[0] == '-')
2188 d = -d;
2189 *(LPDWORD)data = d;
Mike McCormackf1d46462006-10-05 13:41:22 +09002190 TRACE("DWORD %i\n",*(LPDWORD)data);
Aric Stewart6e160f12004-06-29 04:07:22 +00002191
Mike McCormackee034ba2005-09-20 11:59:14 +00002192 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002193 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002194 }
2195 else
2196 {
Aric Stewart54c67dd2005-01-25 20:17:09 +00002197 static const WCHAR szMulti[] = {'[','~',']',0};
Aric Stewart09b0aba2005-06-09 20:30:59 +00002198 LPCWSTR ptr;
Aric Stewart6e160f12004-06-29 04:07:22 +00002199 *type=REG_SZ;
2200
Aric Stewart401bd3f2004-06-28 20:34:35 +00002201 if (value[0]=='#')
Aric Stewart6e160f12004-06-29 04:07:22 +00002202 {
2203 if (value[1]=='%')
2204 {
2205 ptr = &value[2];
2206 *type=REG_EXPAND_SZ;
2207 }
2208 else
2209 ptr = &value[1];
2210 }
2211 else
Aric Stewart401bd3f2004-06-28 20:34:35 +00002212 ptr=value;
2213
Aric Stewart54c67dd2005-01-25 20:17:09 +00002214 if (strstrW(value,szMulti))
2215 *type = REG_MULTI_SZ;
2216
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002217 *size = deformat_string(package, ptr,(LPWSTR*)&data);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002218 }
2219 return data;
2220}
2221
Aric Stewart92ef78e2005-06-21 20:21:18 +00002222static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2223{
2224 MSIPACKAGE *package = (MSIPACKAGE*)param;
2225 static const WCHAR szHCR[] =
2226 {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2227 'R','O','O','T','\\',0};
2228 static const WCHAR szHCU[] =
2229 {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2230 'U','S','E','R','\\',0};
2231 static const WCHAR szHLM[] =
2232 {'H','K','E','Y','_','L','O','C','A','L','_',
2233 'M','A','C','H','I','N','E','\\',0};
2234 static const WCHAR szHU[] =
2235 {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2236
2237 LPSTR value_data = NULL;
2238 HKEY root_key, hkey;
2239 DWORD type,size;
2240 LPWSTR deformated;
2241 LPCWSTR szRoot, component, name, key, value;
Mike McCormack38d67a42005-08-22 09:15:23 +00002242 MSICOMPONENT *comp;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002243 MSIRECORD * uirow;
2244 LPWSTR uikey;
2245 INT root;
2246 BOOL check_first = FALSE;
2247 UINT rc;
2248
2249 ui_progress(package,2,0,0,0);
2250
2251 value = NULL;
2252 key = NULL;
2253 uikey = NULL;
2254 name = NULL;
2255
2256 component = MSI_RecordGetString(row, 6);
Mike McCormack38d67a42005-08-22 09:15:23 +00002257 comp = get_loaded_component(package,component);
Johan Dahlin0946c422005-08-24 10:57:27 +00002258 if (!comp)
2259 return ERROR_SUCCESS;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002260
Mike McCormackd693f462005-10-29 11:36:48 +00002261 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewart92ef78e2005-06-21 20:21:18 +00002262 {
2263 TRACE("Skipping write due to disabled component %s\n",
2264 debugstr_w(component));
2265
Mike McCormack38d67a42005-08-22 09:15:23 +00002266 comp->Action = comp->Installed;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002267
2268 return ERROR_SUCCESS;
2269 }
2270
Mike McCormack38d67a42005-08-22 09:15:23 +00002271 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002272
2273 name = MSI_RecordGetString(row, 4);
2274 if( MSI_RecordIsNull(row,5) && name )
2275 {
2276 /* null values can have special meanings */
2277 if (name[0]=='-' && name[1] == 0)
2278 return ERROR_SUCCESS;
2279 else if ((name[0]=='+' && name[1] == 0) ||
2280 (name[0] == '*' && name[1] == 0))
2281 name = NULL;
2282 check_first = TRUE;
2283 }
2284
2285 root = MSI_RecordGetInteger(row,2);
2286 key = MSI_RecordGetString(row, 3);
2287
2288 /* get the root key */
2289 switch (root)
2290 {
Aric Stewart0713f092005-06-24 11:51:29 +00002291 case -1:
2292 {
2293 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
Mike McCormack062ad502005-09-15 15:04:08 +00002294 LPWSTR all_users = msi_dup_property( package, szALLUSER );
Aric Stewart0713f092005-06-24 11:51:29 +00002295 if (all_users && all_users[0] == '1')
2296 {
2297 root_key = HKEY_LOCAL_MACHINE;
2298 szRoot = szHLM;
2299 }
2300 else
2301 {
2302 root_key = HKEY_CURRENT_USER;
2303 szRoot = szHCU;
2304 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002305 msi_free(all_users);
Aric Stewart0713f092005-06-24 11:51:29 +00002306 }
2307 break;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002308 case 0: root_key = HKEY_CLASSES_ROOT;
2309 szRoot = szHCR;
2310 break;
2311 case 1: root_key = HKEY_CURRENT_USER;
2312 szRoot = szHCU;
2313 break;
2314 case 2: root_key = HKEY_LOCAL_MACHINE;
2315 szRoot = szHLM;
2316 break;
2317 case 3: root_key = HKEY_USERS;
2318 szRoot = szHU;
2319 break;
2320 default:
2321 ERR("Unknown root %i\n",root);
2322 root_key=NULL;
2323 szRoot = NULL;
2324 break;
2325 }
2326 if (!root_key)
2327 return ERROR_SUCCESS;
2328
2329 deformat_string(package, key , &deformated);
2330 size = strlenW(deformated) + strlenW(szRoot) + 1;
Mike McCormackee034ba2005-09-20 11:59:14 +00002331 uikey = msi_alloc(size*sizeof(WCHAR));
Aric Stewart92ef78e2005-06-21 20:21:18 +00002332 strcpyW(uikey,szRoot);
2333 strcatW(uikey,deformated);
2334
2335 if (RegCreateKeyW( root_key, deformated, &hkey))
2336 {
2337 ERR("Could not create key %s\n",debugstr_w(deformated));
Mike McCormackee034ba2005-09-20 11:59:14 +00002338 msi_free(deformated);
2339 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002340 return ERROR_SUCCESS;
2341 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002342 msi_free(deformated);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002343
2344 value = MSI_RecordGetString(row,5);
2345 if (value)
2346 value_data = parse_value(package, value, &type, &size);
2347 else
2348 {
2349 static const WCHAR szEmpty[] = {0};
2350 value_data = (LPSTR)strdupW(szEmpty);
2351 size = 0;
2352 type = REG_SZ;
2353 }
2354
2355 deformat_string(package, name, &deformated);
2356
2357 /* get the double nulls to terminate SZ_MULTI */
2358 if (type == REG_MULTI_SZ)
2359 size +=sizeof(WCHAR);
2360
2361 if (!check_first)
2362 {
2363 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2364 debugstr_w(uikey));
Mike McCormack16466af2005-07-06 10:33:30 +00002365 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002366 }
2367 else
2368 {
2369 DWORD sz = 0;
2370 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2371 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2372 {
2373 TRACE("value %s of %s checked already exists\n",
2374 debugstr_w(deformated), debugstr_w(uikey));
2375 }
2376 else
2377 {
2378 TRACE("Checked and setting value %s of %s\n",
2379 debugstr_w(deformated), debugstr_w(uikey));
2380 if (deformated || size)
Mike McCormack16466af2005-07-06 10:33:30 +00002381 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002382 }
2383 }
2384 RegCloseKey(hkey);
2385
2386 uirow = MSI_CreateRecord(3);
2387 MSI_RecordSetStringW(uirow,2,deformated);
2388 MSI_RecordSetStringW(uirow,1,uikey);
2389
2390 if (type == REG_SZ)
2391 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2392 else
2393 MSI_RecordSetStringW(uirow,3,value);
2394
2395 ui_actiondata(package,szWriteRegistryValues,uirow);
2396 msiobj_release( &uirow->hdr );
2397
Mike McCormackee034ba2005-09-20 11:59:14 +00002398 msi_free(value_data);
2399 msi_free(deformated);
2400 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002401
2402 return ERROR_SUCCESS;
2403}
2404
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002405static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00002406{
2407 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002408 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002409 static const WCHAR ExecSeqQuery[] =
2410 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002411 '`','R','e','g','i','s','t','r','y','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00002412
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002413 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002414 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002415 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00002416
Aric Stewartd2c395a2004-07-06 18:48:15 +00002417 /* increment progress bar each time action data is sent */
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002418 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002419
Aric Stewart92ef78e2005-06-21 20:21:18 +00002420 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002421
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002422 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002423 return rc;
2424}
2425
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002426static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002427{
Aric Stewart9cd707d2005-05-27 19:24:22 +00002428 package->script->CurrentlyScripting = TRUE;
2429
Aric Stewart7d3e5972004-07-04 00:36:58 +00002430 return ERROR_SUCCESS;
2431}
2432
Aric Stewartae1aa322004-12-27 19:02:59 +00002433
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002434static UINT ACTION_InstallValidate(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002435{
Mike McCormack38d67a42005-08-22 09:15:23 +00002436 MSICOMPONENT *comp;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002437 DWORD progress = 0;
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002438 DWORD total = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002439 static const WCHAR q1[]=
2440 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002441 '`','R','e','g','i','s','t','r','y','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002442 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002443 MSIQUERY * view;
Mike McCormack1da28582005-08-22 14:09:17 +00002444 MSIFEATURE *feature;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002445 MSIFILE *file;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002446
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002447 TRACE("InstallValidate\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002448
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002449 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002450 if (rc == ERROR_SUCCESS)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002451 {
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002452 MSI_IterateRecords( view, &progress, NULL, package );
2453 msiobj_release( &view->hdr );
2454 total += progress * REG_PROGRESS_VALUE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002455 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002456
Mike McCormack38d67a42005-08-22 09:15:23 +00002457 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Mike McCormack38d67a42005-08-22 09:15:23 +00002458 total += COMPONENT_PROGRESS_VALUE;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002459
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002460 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002461 total += file->FileSize;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002462
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002463 ui_progress(package,0,total,0,0);
Aric Stewart7d3e5972004-07-04 00:36:58 +00002464
Mike McCormack1da28582005-08-22 14:09:17 +00002465 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002466 {
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002467 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2468 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2469 feature->ActionRequest);
2470 }
2471
Aric Stewart7d3e5972004-07-04 00:36:58 +00002472 return ERROR_SUCCESS;
2473}
2474
Aric Stewartc79f4e22005-06-22 18:03:08 +00002475static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2476{
2477 MSIPACKAGE* package = (MSIPACKAGE*)param;
2478 LPCWSTR cond = NULL;
2479 LPCWSTR message = NULL;
2480 static const WCHAR title[]=
2481 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2482
2483 cond = MSI_RecordGetString(row,1);
2484
2485 if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2486 {
2487 LPWSTR deformated;
2488 message = MSI_RecordGetString(row,2);
2489 deformat_string(package,message,&deformated);
2490 MessageBoxW(NULL,deformated,title,MB_OK);
Mike McCormackee034ba2005-09-20 11:59:14 +00002491 msi_free(deformated);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002492 return ERROR_FUNCTION_FAILED;
2493 }
2494
2495 return ERROR_SUCCESS;
2496}
2497
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002498static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
Aric Stewart5b936ca2004-07-06 18:47:09 +00002499{
2500 UINT rc;
Mike McCormackf3c8b832004-07-19 19:35:05 +00002501 MSIQUERY * view = NULL;
Aric Stewart8e233e92005-03-01 11:45:19 +00002502 static const WCHAR ExecSeqQuery[] =
2503 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002504 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002505
Aric Stewart5b936ca2004-07-06 18:47:09 +00002506 TRACE("Checking launch conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002507
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002508 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart5b936ca2004-07-06 18:47:09 +00002509 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002510 return ERROR_SUCCESS;
Aric Stewart5b936ca2004-07-06 18:47:09 +00002511
Aric Stewartc79f4e22005-06-22 18:03:08 +00002512 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002513 msiobj_release(&view->hdr);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002514
Aric Stewart5b936ca2004-07-06 18:47:09 +00002515 return rc;
2516}
Aric Stewart7d3e5972004-07-04 00:36:58 +00002517
Mike McCormack38d67a42005-08-22 09:15:23 +00002518static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
Aric Stewartb942e182004-07-06 18:50:02 +00002519{
Aric Stewartb942e182004-07-06 18:50:02 +00002520
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002521 if (!cmp->KeyPath)
2522 return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2523
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002524 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
Aric Stewartb942e182004-07-06 18:50:02 +00002525 {
Aric Stewart6269f002005-01-17 13:40:39 +00002526 MSIRECORD * row = 0;
Mike McCormack0b352c72005-06-02 10:29:57 +00002527 UINT root,len;
Aric Stewart09b0aba2005-06-09 20:30:59 +00002528 LPWSTR deformated,buffer,deformated_name;
2529 LPCWSTR key,name;
Aric Stewart8e233e92005-03-01 11:45:19 +00002530 static const WCHAR ExecSeqQuery[] =
2531 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002532 '`','R','e','g','i','s','t','r','y','`',' ',
2533 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2534 ' ','=',' ' ,'\'','%','s','\'',0 };
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002535 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00002536 static const WCHAR fmt2[]=
2537 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
Aric Stewart6269f002005-01-17 13:40:39 +00002538
Mike McCormack0b352c72005-06-02 10:29:57 +00002539 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2540 if (!row)
Aric Stewart6269f002005-01-17 13:40:39 +00002541 return NULL;
2542
Aric Stewart6269f002005-01-17 13:40:39 +00002543 root = MSI_RecordGetInteger(row,2);
Aric Stewart09b0aba2005-06-09 20:30:59 +00002544 key = MSI_RecordGetString(row, 3);
2545 name = MSI_RecordGetString(row, 4);
Aric Stewart6269f002005-01-17 13:40:39 +00002546 deformat_string(package, key , &deformated);
2547 deformat_string(package, name, &deformated_name);
2548
Ulrich Czekallae15e5172005-03-08 16:44:51 +00002549 len = strlenW(deformated) + 6;
Aric Stewart6269f002005-01-17 13:40:39 +00002550 if (deformated_name)
2551 len+=strlenW(deformated_name);
2552
Mike McCormackee034ba2005-09-20 11:59:14 +00002553 buffer = msi_alloc( len *sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00002554
2555 if (deformated_name)
2556 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2557 else
2558 sprintfW(buffer,fmt,root,deformated);
2559
Mike McCormackee034ba2005-09-20 11:59:14 +00002560 msi_free(deformated);
2561 msi_free(deformated_name);
Aric Stewart6269f002005-01-17 13:40:39 +00002562 msiobj_release(&row->hdr);
Aric Stewart6269f002005-01-17 13:40:39 +00002563
2564 return buffer;
2565 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002566 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewart6269f002005-01-17 13:40:39 +00002567 {
2568 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
Aric Stewartfa384f62004-12-22 18:46:17 +00002569 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002570 }
2571 else
2572 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002573 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
Aric Stewartfcb20c52004-07-06 18:51:16 +00002574
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002575 if (file)
2576 return strdupW( file->TargetPath );
Aric Stewartb942e182004-07-06 18:50:02 +00002577 }
Aric Stewartfa384f62004-12-22 18:46:17 +00002578 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002579}
2580
Stefan Huehnerac6f5622005-06-20 14:18:03 +00002581static HKEY openSharedDLLsKey(void)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002582{
2583 HKEY hkey=0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002584 static const WCHAR path[] =
2585 {'S','o','f','t','w','a','r','e','\\',
2586 'M','i','c','r','o','s','o','f','t','\\',
2587 'W','i','n','d','o','w','s','\\',
2588 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2589 'S','h','a','r','e','d','D','L','L','s',0};
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002590
2591 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2592 return hkey;
2593}
2594
2595static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2596{
2597 HKEY hkey;
2598 DWORD count=0;
2599 DWORD type;
2600 DWORD sz = sizeof(count);
2601 DWORD rc;
2602
2603 hkey = openSharedDLLsKey();
2604 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2605 if (rc != ERROR_SUCCESS)
2606 count = 0;
2607 RegCloseKey(hkey);
2608 return count;
2609}
2610
2611static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2612{
2613 HKEY hkey;
2614
2615 hkey = openSharedDLLsKey();
2616 if (count > 0)
Mike McCormack4db02cd2005-09-15 14:58:38 +00002617 msi_reg_set_val_dword( hkey, path, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002618 else
2619 RegDeleteValueW(hkey,path);
2620 RegCloseKey(hkey);
2621 return count;
2622}
2623
2624/*
2625 * Return TRUE if the count should be written out and FALSE if not
2626 */
Mike McCormack38d67a42005-08-22 09:15:23 +00002627static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002628{
Mike McCormack1da28582005-08-22 14:09:17 +00002629 MSIFEATURE *feature;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002630 INT count = 0;
2631 BOOL write = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002632
2633 /* only refcount DLLs */
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002634 if (comp->KeyPath == NULL ||
Mike McCormack38d67a42005-08-22 09:15:23 +00002635 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2636 comp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002637 write = FALSE;
2638 else
2639 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002640 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002641 write = (count > 0);
2642
Mike McCormack38d67a42005-08-22 09:15:23 +00002643 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002644 write = TRUE;
2645 }
2646
2647 /* increment counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002648 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002649 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002650 ComponentList *cl;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002651
Mike McCormack1da28582005-08-22 14:09:17 +00002652 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002653 continue;
2654
Mike McCormack1da28582005-08-22 14:09:17 +00002655 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002656 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002657 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002658 count++;
2659 }
2660 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002661
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002662 /* decrement counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002663 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002664 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002665 ComponentList *cl;
2666
Mike McCormack1da28582005-08-22 14:09:17 +00002667 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002668 continue;
2669
Mike McCormack1da28582005-08-22 14:09:17 +00002670 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002671 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002672 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002673 count--;
2674 }
2675 }
2676
2677 /* ref count all the files in the component */
2678 if (write)
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002679 {
2680 MSIFILE *file;
2681
2682 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002683 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002684 if (file->Component == comp)
2685 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002686 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002687 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002688
2689 /* add a count for permenent */
Mike McCormack38d67a42005-08-22 09:15:23 +00002690 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002691 count ++;
2692
Mike McCormack38d67a42005-08-22 09:15:23 +00002693 comp->RefCount = count;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002694
2695 if (write)
Mike McCormack38d67a42005-08-22 09:15:23 +00002696 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002697}
2698
Aric Stewart2cf222f2004-07-06 19:00:23 +00002699/*
2700 * Ok further analysis makes me think that this work is
2701 * actually done in the PublishComponents and PublishFeatures
Mike McCormack3ece2462004-07-09 19:33:25 +00002702 * step, and not here. It appears like the keypath and all that is
2703 * resolved in this step, however actually written in the Publish steps.
Alexandre Julliard77b12762004-07-09 19:43:29 +00002704 * But we will leave it here for now because it is unclear
Aric Stewart2cf222f2004-07-06 19:00:23 +00002705 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002706static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
Aric Stewartb942e182004-07-06 18:50:02 +00002707{
Aric Stewart68b07492005-01-25 11:05:37 +00002708 WCHAR squished_pc[GUID_SIZE];
2709 WCHAR squished_cc[GUID_SIZE];
Aric Stewartb942e182004-07-06 18:50:02 +00002710 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00002711 MSICOMPONENT *comp;
Aric Stewart68b07492005-01-25 11:05:37 +00002712 HKEY hkey=0,hkey2=0;
Aric Stewartb942e182004-07-06 18:50:02 +00002713
Aric Stewartb942e182004-07-06 18:50:02 +00002714 /* writes the Component and Features values to the registry */
Aric Stewartb942e182004-07-06 18:50:02 +00002715
Aric Stewart68b07492005-01-25 11:05:37 +00002716 rc = MSIREG_OpenComponents(&hkey);
Aric Stewartb942e182004-07-06 18:50:02 +00002717 if (rc != ERROR_SUCCESS)
Mike McCormackfe8cd382006-03-09 14:21:37 +09002718 return rc;
2719
Aric Stewartadaef112005-07-07 20:27:06 +00002720 squash_guid(package->ProductCode,squished_pc);
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002721 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
Mike McCormack38d67a42005-08-22 09:15:23 +00002722
2723 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewartb942e182004-07-06 18:50:02 +00002724 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002725 MSIRECORD * uirow;
2726
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002727 ui_progress(package,2,0,0,0);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002728 if (!comp->ComponentId)
2729 continue;
Aric Stewartb942e182004-07-06 18:50:02 +00002730
Mike McCormackfe8cd382006-03-09 14:21:37 +09002731 squash_guid(comp->ComponentId,squished_cc);
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002732
Mike McCormackfe8cd382006-03-09 14:21:37 +09002733 msi_free(comp->FullKeypath);
2734 comp->FullKeypath = resolve_keypath( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002735
Mike McCormackfe8cd382006-03-09 14:21:37 +09002736 /* do the refcounting */
2737 ACTION_RefCountComponent( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002738
Mike McCormackfe8cd382006-03-09 14:21:37 +09002739 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
Mike McCormack38d67a42005-08-22 09:15:23 +00002740 debugstr_w(comp->Component),
Aric Stewartc5a14432005-05-18 17:46:12 +00002741 debugstr_w(squished_cc),
Mike McCormackfe8cd382006-03-09 14:21:37 +09002742 debugstr_w(comp->FullKeypath),
Mike McCormack38d67a42005-08-22 09:15:23 +00002743 comp->RefCount);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002744 /*
2745 * Write the keypath out if the component is to be registered
2746 * and delete the key if the component is to be deregistered
2747 */
2748 if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2749 {
2750 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2751 if (rc != ERROR_SUCCESS)
2752 continue;
2753
2754 if (!comp->FullKeypath)
2755 continue;
2756
2757 msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2758
2759 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartfa384f62004-12-22 18:46:17 +00002760 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09002761 static const WCHAR szPermKey[] =
2762 { '0','0','0','0','0','0','0','0','0','0','0','0',
2763 '0','0','0','0','0','0','0','0','0','0','0','0',
2764 '0','0','0','0','0','0','0','0',0 };
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002765
Mike McCormackfe8cd382006-03-09 14:21:37 +09002766 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002767 }
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002768
Mike McCormackfe8cd382006-03-09 14:21:37 +09002769 RegCloseKey(hkey2);
Mike McCormackfe8cd382006-03-09 14:21:37 +09002770 }
2771 else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2772 {
2773 DWORD res;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002774
Mike McCormackfe8cd382006-03-09 14:21:37 +09002775 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2776 if (rc != ERROR_SUCCESS)
2777 continue;
2778
2779 RegDeleteValueW(hkey2,squished_pc);
2780
2781 /* if the key is empty delete it */
2782 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2783 RegCloseKey(hkey2);
2784 if (res == ERROR_NO_MORE_ITEMS)
2785 RegDeleteKeyW(hkey,squished_cc);
2786
Aric Stewartb942e182004-07-06 18:50:02 +00002787 }
Mike McCormacka3a2eae2006-11-29 16:36:58 +09002788
2789 /* UI stuff */
2790 uirow = MSI_CreateRecord(3);
2791 MSI_RecordSetStringW(uirow,1,package->ProductCode);
2792 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2793 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2794 ui_actiondata(package,szProcessComponents,uirow);
2795 msiobj_release( &uirow->hdr );
2796 }
Aric Stewartb942e182004-07-06 18:50:02 +00002797 RegCloseKey(hkey);
2798 return rc;
2799}
2800
Aric Stewart6e821732005-03-30 10:19:08 +00002801typedef struct {
2802 CLSID clsid;
2803 LPWSTR source;
2804
2805 LPWSTR path;
2806 ITypeLib *ptLib;
2807} typelib_struct;
2808
Mike McCormackf9acfe62005-06-07 20:29:51 +00002809static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
Aric Stewart6e821732005-03-30 10:19:08 +00002810 LPWSTR lpszName, LONG_PTR lParam)
2811{
2812 TLIBATTR *attr;
2813 typelib_struct *tl_struct = (typelib_struct*) lParam;
2814 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2815 int sz;
2816 HRESULT res;
2817
2818 if (!IS_INTRESOURCE(lpszName))
2819 {
2820 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2821 return TRUE;
2822 }
2823
2824 sz = strlenW(tl_struct->source)+4;
2825 sz *= sizeof(WCHAR);
2826
Mike McCormack2acf8002006-05-25 11:41:39 +09002827 if ((INT_PTR)lpszName == 1)
Aric Stewartca8c4e42005-06-02 15:13:57 +00002828 tl_struct->path = strdupW(tl_struct->source);
2829 else
2830 {
Mike McCormackee034ba2005-09-20 11:59:14 +00002831 tl_struct->path = msi_alloc(sz);
Aric Stewartca8c4e42005-06-02 15:13:57 +00002832 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2833 }
Aric Stewart6e821732005-03-30 10:19:08 +00002834
2835 TRACE("trying %s\n", debugstr_w(tl_struct->path));
2836 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2837 if (!SUCCEEDED(res))
2838 {
Mike McCormackee034ba2005-09-20 11:59:14 +00002839 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00002840 tl_struct->path = NULL;
2841
2842 return TRUE;
2843 }
2844
2845 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2846 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2847 {
2848 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2849 return FALSE;
2850 }
2851
Mike McCormackee034ba2005-09-20 11:59:14 +00002852 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00002853 tl_struct->path = NULL;
2854
2855 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2856 ITypeLib_Release(tl_struct->ptLib);
2857
2858 return TRUE;
2859}
2860
Aric Stewart234dc4b2005-06-22 18:27:34 +00002861static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2862{
2863 MSIPACKAGE* package = (MSIPACKAGE*)param;
2864 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00002865 MSICOMPONENT *comp;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002866 MSIFILE *file;
Aric Stewart234dc4b2005-06-22 18:27:34 +00002867 typelib_struct tl_struct;
2868 HMODULE module;
2869 static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2870
2871 component = MSI_RecordGetString(row,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00002872 comp = get_loaded_component(package,component);
2873 if (!comp)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002874 return ERROR_SUCCESS;
2875
Mike McCormackd693f462005-10-29 11:36:48 +00002876 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewart234dc4b2005-06-22 18:27:34 +00002877 {
2878 TRACE("Skipping typelib reg due to disabled component\n");
2879
Mike McCormack38d67a42005-08-22 09:15:23 +00002880 comp->Action = comp->Installed;
Aric Stewart234dc4b2005-06-22 18:27:34 +00002881
2882 return ERROR_SUCCESS;
2883 }
2884
Mike McCormack38d67a42005-08-22 09:15:23 +00002885 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart234dc4b2005-06-22 18:27:34 +00002886
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002887 file = get_loaded_file( package, comp->KeyPath );
2888 if (!file)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002889 return ERROR_SUCCESS;
2890
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002891 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
Mike McCormack51c66182005-10-27 12:36:12 +00002892 if (module)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002893 {
Mike McCormack51c66182005-10-27 12:36:12 +00002894 LPCWSTR guid;
2895 guid = MSI_RecordGetString(row,1);
2896 CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002897 tl_struct.source = strdupW( file->TargetPath );
Aric Stewart234dc4b2005-06-22 18:27:34 +00002898 tl_struct.path = NULL;
2899
2900 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2901 (LONG_PTR)&tl_struct);
2902
Mike McCormack51c66182005-10-27 12:36:12 +00002903 if (tl_struct.path)
Aric Stewart234dc4b2005-06-22 18:27:34 +00002904 {
2905 LPWSTR help = NULL;
2906 LPCWSTR helpid;
2907 HRESULT res;
2908
2909 helpid = MSI_RecordGetString(row,6);
2910
2911 if (helpid)
2912 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2913 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
Mike McCormackee034ba2005-09-20 11:59:14 +00002914 msi_free(help);
Aric Stewart234dc4b2005-06-22 18:27:34 +00002915
2916 if (!SUCCEEDED(res))
2917 ERR("Failed to register type library %s\n",
2918 debugstr_w(tl_struct.path));
2919 else
2920 {
2921 ui_actiondata(package,szRegisterTypeLibraries,row);
2922
2923 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2924 }
2925
2926 ITypeLib_Release(tl_struct.ptLib);
Mike McCormackee034ba2005-09-20 11:59:14 +00002927 msi_free(tl_struct.path);
Aric Stewart234dc4b2005-06-22 18:27:34 +00002928 }
2929 else
2930 ERR("Failed to load type library %s\n",
2931 debugstr_w(tl_struct.source));
2932
2933 FreeLibrary(module);
Mike McCormackee034ba2005-09-20 11:59:14 +00002934 msi_free(tl_struct.source);
Aric Stewart234dc4b2005-06-22 18:27:34 +00002935 }
2936 else
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002937 ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
Aric Stewart234dc4b2005-06-22 18:27:34 +00002938
2939 return ERROR_SUCCESS;
2940}
2941
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002942static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
Aric Stewartfcb20c52004-07-06 18:51:16 +00002943{
2944 /*
Mike McCormackc90c7812004-07-09 22:58:27 +00002945 * OK this is a bit confusing.. I am given a _Component key and I believe
Aric Stewartfcb20c52004-07-06 18:51:16 +00002946 * that the file that is being registered as a type library is the "key file
Mike McCormackc90c7812004-07-09 22:58:27 +00002947 * of that component" which I interpret to mean "The file in the KeyPath of
2948 * that component".
Aric Stewartfcb20c52004-07-06 18:51:16 +00002949 */
2950 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002951 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002952 static const WCHAR Query[] =
2953 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002954 '`','T','y','p','e','L','i','b','`',0};
Aric Stewartfcb20c52004-07-06 18:51:16 +00002955
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002956 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewartfcb20c52004-07-06 18:51:16 +00002957 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002958 return ERROR_SUCCESS;
Aric Stewartfcb20c52004-07-06 18:51:16 +00002959
Aric Stewart234dc4b2005-06-22 18:27:34 +00002960 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002961 msiobj_release(&view->hdr);
Aric Stewartfcb20c52004-07-06 18:51:16 +00002962 return rc;
Aric Stewartfcb20c52004-07-06 18:51:16 +00002963}
2964
Aric Stewart9adacf62005-06-24 11:58:21 +00002965static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
Aric Stewart2cf222f2004-07-06 19:00:23 +00002966{
Aric Stewart9adacf62005-06-24 11:58:21 +00002967 MSIPACKAGE *package = (MSIPACKAGE*)param;
Mike McCormack477bce32006-01-16 20:38:28 +01002968 LPWSTR target_file, target_folder, filename;
Robert Shearman4ac85672006-02-22 16:31:00 +00002969 LPCWSTR buffer, extension;
Mike McCormack38d67a42005-08-22 09:15:23 +00002970 MSICOMPONENT *comp;
Aric Stewart9adacf62005-06-24 11:58:21 +00002971 static const WCHAR szlnk[]={'.','l','n','k',0};
Mike McCormack20c57462006-05-24 17:41:04 +09002972 IShellLinkW *sl = NULL;
2973 IPersistFile *pf = NULL;
Aric Stewart2cf222f2004-07-06 19:00:23 +00002974 HRESULT res;
2975
Aric Stewart9adacf62005-06-24 11:58:21 +00002976 buffer = MSI_RecordGetString(row,4);
Mike McCormack38d67a42005-08-22 09:15:23 +00002977 comp = get_loaded_component(package,buffer);
2978 if (!comp)
Aric Stewart9adacf62005-06-24 11:58:21 +00002979 return ERROR_SUCCESS;
2980
Mike McCormackd693f462005-10-29 11:36:48 +00002981 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
Aric Stewart9adacf62005-06-24 11:58:21 +00002982 {
2983 TRACE("Skipping shortcut creation due to disabled component\n");
2984
Mike McCormack38d67a42005-08-22 09:15:23 +00002985 comp->Action = comp->Installed;
Aric Stewart9adacf62005-06-24 11:58:21 +00002986
2987 return ERROR_SUCCESS;
2988 }
2989
Mike McCormack38d67a42005-08-22 09:15:23 +00002990 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart9adacf62005-06-24 11:58:21 +00002991
2992 ui_actiondata(package,szCreateShortcuts,row);
2993
2994 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2995 &IID_IShellLinkW, (LPVOID *) &sl );
2996
Mike McCormack20c57462006-05-24 17:41:04 +09002997 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00002998 {
Mike McCormack20c57462006-05-24 17:41:04 +09002999 ERR("CLSID_ShellLink not available\n");
3000 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003001 }
3002
3003 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
Mike McCormack20c57462006-05-24 17:41:04 +09003004 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003005 {
Mike McCormack20c57462006-05-24 17:41:04 +09003006 ERR("QueryInterface(IID_IPersistFile) failed\n");
3007 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003008 }
3009
3010 buffer = MSI_RecordGetString(row,2);
3011 target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
3012
3013 /* may be needed because of a bug somehwere else */
3014 create_full_pathW(target_folder);
3015
Mike McCormack477bce32006-01-16 20:38:28 +01003016 filename = msi_dup_record_field( row, 3 );
Aric Stewart9adacf62005-06-24 11:58:21 +00003017 reduce_to_longfilename(filename);
Robert Shearman4ac85672006-02-22 16:31:00 +00003018
3019 extension = strchrW(filename,'.');
3020 if (!extension || strcmpiW(extension,szlnk))
3021 {
3022 int len = strlenW(filename);
3023 filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
3024 memcpy(filename + len, szlnk, sizeof(szlnk));
3025 }
Aric Stewart9adacf62005-06-24 11:58:21 +00003026 target_file = build_directory_name(2, target_folder, filename);
Mike McCormackee034ba2005-09-20 11:59:14 +00003027 msi_free(target_folder);
Mike McCormack477bce32006-01-16 20:38:28 +01003028 msi_free(filename);
Aric Stewart9adacf62005-06-24 11:58:21 +00003029
3030 buffer = MSI_RecordGetString(row,5);
3031 if (strchrW(buffer,'['))
3032 {
3033 LPWSTR deformated;
3034 deformat_string(package,buffer,&deformated);
3035 IShellLinkW_SetPath(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003036 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003037 }
3038 else
3039 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003040 FIXME("poorly handled shortcut format, advertised shortcut\n");
Mike McCormack566c69e2005-09-22 10:49:17 +00003041 IShellLinkW_SetPath(sl,comp->FullKeypath);
Aric Stewart9adacf62005-06-24 11:58:21 +00003042 }
3043
3044 if (!MSI_RecordIsNull(row,6))
3045 {
3046 LPWSTR deformated;
3047 buffer = MSI_RecordGetString(row,6);
3048 deformat_string(package,buffer,&deformated);
3049 IShellLinkW_SetArguments(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003050 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003051 }
3052
3053 if (!MSI_RecordIsNull(row,7))
3054 {
3055 buffer = MSI_RecordGetString(row,7);
3056 IShellLinkW_SetDescription(sl,buffer);
3057 }
3058
3059 if (!MSI_RecordIsNull(row,8))
3060 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3061
3062 if (!MSI_RecordIsNull(row,9))
3063 {
Mike McCormack75658d72005-09-22 10:33:57 +00003064 LPWSTR Path;
Aric Stewart9adacf62005-06-24 11:58:21 +00003065 INT index;
3066
3067 buffer = MSI_RecordGetString(row,9);
3068
Mike McCormack75658d72005-09-22 10:33:57 +00003069 Path = build_icon_path(package,buffer);
Aric Stewart9adacf62005-06-24 11:58:21 +00003070 index = MSI_RecordGetInteger(row,10);
3071
Robert Shearmanab378802006-08-03 20:24:10 +01003072 /* no value means 0 */
3073 if (index == MSI_NULL_INTEGER)
3074 index = 0;
3075
Aric Stewart9adacf62005-06-24 11:58:21 +00003076 IShellLinkW_SetIconLocation(sl,Path,index);
Mike McCormackee034ba2005-09-20 11:59:14 +00003077 msi_free(Path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003078 }
3079
3080 if (!MSI_RecordIsNull(row,11))
3081 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3082
3083 if (!MSI_RecordIsNull(row,12))
3084 {
3085 LPWSTR Path;
3086 buffer = MSI_RecordGetString(row,12);
3087 Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
Mike McCormack43f7f3e2006-07-27 23:18:15 +09003088 if (Path)
3089 IShellLinkW_SetWorkingDirectory(sl,Path);
Mike McCormackee034ba2005-09-20 11:59:14 +00003090 msi_free(Path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003091 }
3092
3093 TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3094 IPersistFile_Save(pf,target_file,FALSE);
3095
Mike McCormackee034ba2005-09-20 11:59:14 +00003096 msi_free(target_file);
Aric Stewart9adacf62005-06-24 11:58:21 +00003097
Mike McCormack20c57462006-05-24 17:41:04 +09003098err:
3099 if (pf)
3100 IPersistFile_Release( pf );
3101 if (sl)
3102 IShellLinkW_Release( sl );
Aric Stewart9adacf62005-06-24 11:58:21 +00003103
3104 return ERROR_SUCCESS;
3105}
3106
3107static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3108{
3109 UINT rc;
3110 HRESULT res;
3111 MSIQUERY * view;
3112 static const WCHAR Query[] =
3113 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3114 '`','S','h','o','r','t','c','u','t','`',0};
3115
Aric Stewart9adacf62005-06-24 11:58:21 +00003116 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3117 if (rc != ERROR_SUCCESS)
3118 return ERROR_SUCCESS;
3119
Aric Stewart2cf222f2004-07-06 19:00:23 +00003120 res = CoInitialize( NULL );
3121 if (FAILED (res))
3122 {
3123 ERR("CoInitialize failed\n");
3124 return ERROR_FUNCTION_FAILED;
3125 }
3126
Aric Stewart9adacf62005-06-24 11:58:21 +00003127 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003128 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003129
Aric Stewart2cf222f2004-07-06 19:00:23 +00003130 CoUninitialize();
3131
3132 return rc;
3133}
3134
Aric Stewart916ef942005-06-22 18:42:19 +00003135static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3136{
3137 MSIPACKAGE* package = (MSIPACKAGE*)param;
3138 HANDLE the_file;
Mike McCormack75658d72005-09-22 10:33:57 +00003139 LPWSTR FilePath;
3140 LPCWSTR FileName;
Aric Stewart916ef942005-06-22 18:42:19 +00003141 CHAR buffer[1024];
3142 DWORD sz;
3143 UINT rc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003144 MSIRECORD *uirow;
Aric Stewart916ef942005-06-22 18:42:19 +00003145
3146 FileName = MSI_RecordGetString(row,1);
3147 if (!FileName)
3148 {
3149 ERR("Unable to get FileName\n");
3150 return ERROR_SUCCESS;
3151 }
3152
Mike McCormack75658d72005-09-22 10:33:57 +00003153 FilePath = build_icon_path(package,FileName);
Aric Stewart916ef942005-06-22 18:42:19 +00003154
3155 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3156
3157 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3158 FILE_ATTRIBUTE_NORMAL, NULL);
3159
3160 if (the_file == INVALID_HANDLE_VALUE)
3161 {
3162 ERR("Unable to create file %s\n",debugstr_w(FilePath));
Mike McCormackee034ba2005-09-20 11:59:14 +00003163 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003164 return ERROR_SUCCESS;
3165 }
3166
3167 do
3168 {
3169 DWORD write;
3170 sz = 1024;
3171 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3172 if (rc != ERROR_SUCCESS)
3173 {
3174 ERR("Failed to get stream\n");
3175 CloseHandle(the_file);
3176 DeleteFileW(FilePath);
3177 break;
3178 }
3179 WriteFile(the_file,buffer,sz,&write,NULL);
3180 } while (sz == 1024);
3181
Mike McCormackee034ba2005-09-20 11:59:14 +00003182 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003183
3184 CloseHandle(the_file);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003185
3186 uirow = MSI_CreateRecord(1);
3187 MSI_RecordSetStringW(uirow,1,FileName);
3188 ui_actiondata(package,szPublishProduct,uirow);
3189 msiobj_release( &uirow->hdr );
3190
Aric Stewart916ef942005-06-22 18:42:19 +00003191 return ERROR_SUCCESS;
3192}
Aric Stewart2cf222f2004-07-06 19:00:23 +00003193
3194/*
3195 * 99% of the work done here is only done for
3196 * advertised installs. However this is where the
3197 * Icon table is processed and written out
Francois Gouget817c5202004-07-16 19:15:40 +00003198 * so that is what I am going to do here.
Aric Stewart2cf222f2004-07-06 19:00:23 +00003199 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003200static UINT ACTION_PublishProduct(MSIPACKAGE *package)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003201{
3202 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003203 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003204 static const WCHAR Query[]=
3205 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003206 '`','I','c','o','n','`',0};
Aric Stewart6269f002005-01-17 13:40:39 +00003207 /* for registry stuff */
Aric Stewart68b07492005-01-25 11:05:37 +00003208 HKEY hkey=0;
3209 HKEY hukey=0;
Aric Stewart6957e4a2005-06-08 19:16:45 +00003210 static const WCHAR szProductLanguage[] =
3211 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
Aric Stewart6957e4a2005-06-08 19:16:45 +00003212 static const WCHAR szARPProductIcon[] =
3213 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
Aric Stewartc28bb542005-06-09 15:49:11 +00003214 static const WCHAR szProductVersion[] =
3215 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
Aric Stewart6957e4a2005-06-08 19:16:45 +00003216 DWORD langid;
Aric Stewart6269f002005-01-17 13:40:39 +00003217 LPWSTR buffer;
3218 DWORD size;
Aric Stewart68b07492005-01-25 11:05:37 +00003219 MSIHANDLE hDb, hSumInfo;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003220
Aric Stewart916ef942005-06-22 18:42:19 +00003221 /* write out icon files */
3222
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003223 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewart916ef942005-06-22 18:42:19 +00003224 if (rc == ERROR_SUCCESS)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003225 {
Aric Stewart916ef942005-06-22 18:42:19 +00003226 MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003227 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003228 }
3229
Francois Gougetda8b3dd2005-01-26 21:09:04 +00003230 /* ok there is a lot more done here but i need to figure out what */
Aric Stewart916ef942005-06-22 18:42:19 +00003231
Aric Stewartadaef112005-07-07 20:27:06 +00003232 rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003233 if (rc != ERROR_SUCCESS)
3234 goto end;
3235
Aric Stewartadaef112005-07-07 20:27:06 +00003236 rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003237 if (rc != ERROR_SUCCESS)
3238 goto end;
3239
Aric Stewart6269f002005-01-17 13:40:39 +00003240
Mike McCormack062ad502005-09-15 15:04:08 +00003241 buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
Mike McCormack4db02cd2005-09-15 14:58:38 +00003242 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00003243 msi_free(buffer);
Aric Stewart6957e4a2005-06-08 19:16:45 +00003244
Mike McCormack74f0de92005-09-29 10:32:39 +00003245 langid = msi_get_property_int( package, szProductLanguage, 0 );
Mike McCormack4db02cd2005-09-15 14:58:38 +00003246 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003247
Mike McCormack062ad502005-09-15 15:04:08 +00003248 buffer = msi_dup_property( package, szARPProductIcon );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003249 if (buffer)
3250 {
Mike McCormack75658d72005-09-22 10:33:57 +00003251 LPWSTR path = build_icon_path(package,buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003252 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
Mike McCormack75658d72005-09-22 10:33:57 +00003253 msi_free( path );
Aric Stewart6957e4a2005-06-08 19:16:45 +00003254 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003255 msi_free(buffer);
Aric Stewartc28bb542005-06-09 15:49:11 +00003256
Mike McCormack062ad502005-09-15 15:04:08 +00003257 buffer = msi_dup_property( package, szProductVersion );
Aric Stewartc28bb542005-06-09 15:49:11 +00003258 if (buffer)
3259 {
Mike McCormack230af9d2006-07-14 15:19:08 +09003260 DWORD verdword = msi_version_str_to_dword(buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003261 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
Aric Stewartc28bb542005-06-09 15:49:11 +00003262 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003263 msi_free(buffer);
Aric Stewart6957e4a2005-06-08 19:16:45 +00003264
Mike McCormackb7270b82005-12-31 13:18:11 +01003265 /* FIXME: Need to write more keys to the user registry */
Aric Stewart68b07492005-01-25 11:05:37 +00003266
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003267 hDb= alloc_msihandle( &package->db->hdr );
Dan Kegel337e1e22006-08-28 09:44:35 -07003268 if (!hDb) {
3269 rc = ERROR_NOT_ENOUGH_MEMORY;
3270 goto end;
3271 }
Aric Stewart68b07492005-01-25 11:05:37 +00003272 rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003273 MsiCloseHandle(hDb);
Aric Stewart68b07492005-01-25 11:05:37 +00003274 if (rc == ERROR_SUCCESS)
3275 {
3276 WCHAR guidbuffer[0x200];
3277 size = 0x200;
Aric Stewart7e7b8cf2005-02-18 20:00:34 +00003278 rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
Aric Stewart68b07492005-01-25 11:05:37 +00003279 guidbuffer, &size);
3280 if (rc == ERROR_SUCCESS)
3281 {
3282 WCHAR squashed[GUID_SIZE];
3283 /* for now we only care about the first guid */
3284 LPWSTR ptr = strchrW(guidbuffer,';');
3285 if (ptr) *ptr = 0;
3286 squash_guid(guidbuffer,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003287 msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
Aric Stewart68b07492005-01-25 11:05:37 +00003288 }
3289 else
3290 {
Francois Gouget0edbaf72005-11-10 12:14:56 +00003291 ERR("Unable to query Revision_Number...\n");
Aric Stewart68b07492005-01-25 11:05:37 +00003292 rc = ERROR_SUCCESS;
3293 }
3294 MsiCloseHandle(hSumInfo);
3295 }
3296 else
3297 {
3298 ERR("Unable to open Summary Information\n");
3299 rc = ERROR_SUCCESS;
3300 }
Aric Stewart2cae30b2005-01-19 19:07:40 +00003301
Aric Stewart6269f002005-01-17 13:40:39 +00003302end:
3303
Aric Stewart6269f002005-01-17 13:40:39 +00003304 RegCloseKey(hkey);
Aric Stewart6269f002005-01-17 13:40:39 +00003305 RegCloseKey(hukey);
3306
Aric Stewart2cf222f2004-07-06 19:00:23 +00003307 return rc;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003308}
3309
Aric Stewartaded32f2005-06-23 09:46:31 +00003310static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3311{
3312 MSIPACKAGE *package = (MSIPACKAGE*)param;
3313 LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3314 LPWSTR deformated_section, deformated_key, deformated_value;
3315 LPWSTR folder, fullname = NULL;
3316 MSIRECORD * uirow;
Mike McCormack38d67a42005-08-22 09:15:23 +00003317 INT action;
3318 MSICOMPONENT *comp;
Aric Stewartaded32f2005-06-23 09:46:31 +00003319 static const WCHAR szWindowsFolder[] =
3320 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3321
3322 component = MSI_RecordGetString(row, 8);
Mike McCormack38d67a42005-08-22 09:15:23 +00003323 comp = get_loaded_component(package,component);
Aric Stewartaded32f2005-06-23 09:46:31 +00003324
Mike McCormackd693f462005-10-29 11:36:48 +00003325 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
Aric Stewartaded32f2005-06-23 09:46:31 +00003326 {
3327 TRACE("Skipping ini file due to disabled component %s\n",
3328 debugstr_w(component));
3329
Mike McCormack38d67a42005-08-22 09:15:23 +00003330 comp->Action = comp->Installed;
Aric Stewartaded32f2005-06-23 09:46:31 +00003331
3332 return ERROR_SUCCESS;
3333 }
3334
Mike McCormack38d67a42005-08-22 09:15:23 +00003335 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewartaded32f2005-06-23 09:46:31 +00003336
3337 identifier = MSI_RecordGetString(row,1);
3338 filename = MSI_RecordGetString(row,2);
3339 dirproperty = MSI_RecordGetString(row,3);
3340 section = MSI_RecordGetString(row,4);
3341 key = MSI_RecordGetString(row,5);
3342 value = MSI_RecordGetString(row,6);
3343 action = MSI_RecordGetInteger(row,7);
3344
3345 deformat_string(package,section,&deformated_section);
3346 deformat_string(package,key,&deformated_key);
3347 deformat_string(package,value,&deformated_value);
3348
3349 if (dirproperty)
3350 {
3351 folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3352 if (!folder)
Mike McCormack062ad502005-09-15 15:04:08 +00003353 folder = msi_dup_property( package, dirproperty );
Aric Stewartaded32f2005-06-23 09:46:31 +00003354 }
3355 else
Mike McCormack062ad502005-09-15 15:04:08 +00003356 folder = msi_dup_property( package, szWindowsFolder );
Aric Stewartaded32f2005-06-23 09:46:31 +00003357
3358 if (!folder)
3359 {
3360 ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3361 goto cleanup;
3362 }
3363
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003364 fullname = build_directory_name(2, folder, filename);
Aric Stewartaded32f2005-06-23 09:46:31 +00003365
3366 if (action == 0)
3367 {
3368 TRACE("Adding value %s to section %s in %s\n",
3369 debugstr_w(deformated_key), debugstr_w(deformated_section),
3370 debugstr_w(fullname));
3371 WritePrivateProfileStringW(deformated_section, deformated_key,
3372 deformated_value, fullname);
3373 }
3374 else if (action == 1)
3375 {
3376 WCHAR returned[10];
3377 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3378 returned, 10, fullname);
3379 if (returned[0] == 0)
3380 {
3381 TRACE("Adding value %s to section %s in %s\n",
3382 debugstr_w(deformated_key), debugstr_w(deformated_section),
3383 debugstr_w(fullname));
3384
3385 WritePrivateProfileStringW(deformated_section, deformated_key,
3386 deformated_value, fullname);
3387 }
3388 }
3389 else if (action == 3)
3390 FIXME("Append to existing section not yet implemented\n");
3391
3392 uirow = MSI_CreateRecord(4);
3393 MSI_RecordSetStringW(uirow,1,identifier);
3394 MSI_RecordSetStringW(uirow,2,deformated_section);
3395 MSI_RecordSetStringW(uirow,3,deformated_key);
3396 MSI_RecordSetStringW(uirow,4,deformated_value);
3397 ui_actiondata(package,szWriteIniValues,uirow);
3398 msiobj_release( &uirow->hdr );
3399cleanup:
Mike McCormackee034ba2005-09-20 11:59:14 +00003400 msi_free(fullname);
3401 msi_free(folder);
3402 msi_free(deformated_key);
3403 msi_free(deformated_value);
3404 msi_free(deformated_section);
Aric Stewartaded32f2005-06-23 09:46:31 +00003405 return ERROR_SUCCESS;
3406}
3407
Aric Stewart516a9c72005-01-14 15:59:26 +00003408static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3409{
3410 UINT rc;
3411 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003412 static const WCHAR ExecSeqQuery[] =
3413 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003414 '`','I','n','i','F','i','l','e','`',0};
Aric Stewart516a9c72005-01-14 15:59:26 +00003415
3416 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3417 if (rc != ERROR_SUCCESS)
3418 {
3419 TRACE("no IniFile table\n");
3420 return ERROR_SUCCESS;
3421 }
3422
Aric Stewartaded32f2005-06-23 09:46:31 +00003423 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
Aric Stewart516a9c72005-01-14 15:59:26 +00003424 msiobj_release(&view->hdr);
3425 return rc;
3426}
3427
Aric Stewart854bfc42005-06-24 11:33:02 +00003428static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
Aric Stewart6269f002005-01-17 13:40:39 +00003429{
Aric Stewart854bfc42005-06-24 11:33:02 +00003430 MSIPACKAGE *package = (MSIPACKAGE*)param;
3431 LPCWSTR filename;
3432 LPWSTR FullName;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003433 MSIFILE *file;
Aric Stewart854bfc42005-06-24 11:33:02 +00003434 DWORD len;
Aric Stewart8e233e92005-03-01 11:45:19 +00003435 static const WCHAR ExeStr[] =
Aric Stewartc5a14432005-05-18 17:46:12 +00003436 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3437 static const WCHAR close[] = {'\"',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00003438 STARTUPINFOW si;
3439 PROCESS_INFORMATION info;
3440 BOOL brc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003441 MSIRECORD *uirow;
3442 LPWSTR uipath, p;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003443
3444 memset(&si,0,sizeof(STARTUPINFOW));
3445
Aric Stewart854bfc42005-06-24 11:33:02 +00003446 filename = MSI_RecordGetString(row,1);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003447 file = get_loaded_file( package, filename );
Aric Stewart854bfc42005-06-24 11:33:02 +00003448
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003449 if (!file)
Aric Stewart854bfc42005-06-24 11:33:02 +00003450 {
3451 ERR("Unable to find file id %s\n",debugstr_w(filename));
3452 return ERROR_SUCCESS;
3453 }
3454
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003455 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
Aric Stewart854bfc42005-06-24 11:33:02 +00003456
Mike McCormackee034ba2005-09-20 11:59:14 +00003457 FullName = msi_alloc(len*sizeof(WCHAR));
Aric Stewart854bfc42005-06-24 11:33:02 +00003458 strcpyW(FullName,ExeStr);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003459 strcatW( FullName, file->TargetPath );
Aric Stewart854bfc42005-06-24 11:33:02 +00003460 strcatW(FullName,close);
3461
3462 TRACE("Registering %s\n",debugstr_w(FullName));
3463 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3464 &si, &info);
3465
3466 if (brc)
3467 msi_dialog_check_messages(info.hProcess);
3468
Mike McCormackee034ba2005-09-20 11:59:14 +00003469 msi_free(FullName);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003470
3471 /* the UI chunk */
3472 uirow = MSI_CreateRecord( 2 );
3473 uipath = strdupW( file->TargetPath );
3474 p = strrchrW(uipath,'\\');
3475 if (p)
3476 p[1]=0;
3477 MSI_RecordSetStringW( uirow, 1, &p[2] );
3478 MSI_RecordSetStringW( uirow, 2, uipath);
3479 ui_actiondata( package, szSelfRegModules, uirow);
3480 msiobj_release( &uirow->hdr );
3481 msi_free( uipath );
3482 /* FIXME: call ui_progress? */
3483
Aric Stewart854bfc42005-06-24 11:33:02 +00003484 return ERROR_SUCCESS;
3485}
3486
3487static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3488{
3489 UINT rc;
3490 MSIQUERY * view;
3491 static const WCHAR ExecSeqQuery[] =
3492 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3493 '`','S','e','l','f','R','e','g','`',0};
3494
Aric Stewart6269f002005-01-17 13:40:39 +00003495 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3496 if (rc != ERROR_SUCCESS)
3497 {
3498 TRACE("no SelfReg table\n");
3499 return ERROR_SUCCESS;
3500 }
3501
Aric Stewart854bfc42005-06-24 11:33:02 +00003502 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
Aric Stewart6269f002005-01-17 13:40:39 +00003503 msiobj_release(&view->hdr);
Aric Stewart854bfc42005-06-24 11:33:02 +00003504
3505 return ERROR_SUCCESS;
Aric Stewart6269f002005-01-17 13:40:39 +00003506}
3507
3508static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3509{
Mike McCormack1da28582005-08-22 14:09:17 +00003510 MSIFEATURE *feature;
Aric Stewart6269f002005-01-17 13:40:39 +00003511 UINT rc;
Aric Stewart68b07492005-01-25 11:05:37 +00003512 HKEY hkey=0;
3513 HKEY hukey=0;
Aric Stewart68b07492005-01-25 11:05:37 +00003514
Aric Stewartadaef112005-07-07 20:27:06 +00003515 rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003516 if (rc != ERROR_SUCCESS)
3517 goto end;
3518
Aric Stewartadaef112005-07-07 20:27:06 +00003519 rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
Aric Stewart6269f002005-01-17 13:40:39 +00003520 if (rc != ERROR_SUCCESS)
3521 goto end;
3522
3523 /* here the guids are base 85 encoded */
Mike McCormack1da28582005-08-22 14:09:17 +00003524 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00003525 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003526 ComponentList *cl;
Aric Stewart6269f002005-01-17 13:40:39 +00003527 LPWSTR data = NULL;
3528 GUID clsid;
Aric Stewart6269f002005-01-17 13:40:39 +00003529 INT size;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003530 BOOL absent = FALSE;
Robert Shearmand2e48e02006-01-23 17:29:50 +01003531 MSIRECORD *uirow;
Aric Stewart6269f002005-01-17 13:40:39 +00003532
Mike McCormack1da28582005-08-22 14:09:17 +00003533 if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3534 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3535 !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003536 absent = TRUE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003537
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003538 size = 1;
Mike McCormack1da28582005-08-22 14:09:17 +00003539 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003540 {
3541 size += 21;
3542 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00003543 if (feature->Feature_Parent)
Mike McCormack1da28582005-08-22 14:09:17 +00003544 size += strlenW( feature->Feature_Parent )+2;
Aric Stewart6269f002005-01-17 13:40:39 +00003545
Mike McCormackee034ba2005-09-20 11:59:14 +00003546 data = msi_alloc(size * sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00003547
3548 data[0] = 0;
Mike McCormack1da28582005-08-22 14:09:17 +00003549 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00003550 {
Mike McCormack38d67a42005-08-22 09:15:23 +00003551 MSICOMPONENT* component = cl->component;
Aric Stewart6269f002005-01-17 13:40:39 +00003552 WCHAR buf[21];
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003553
Mike McCormack3a940112006-04-19 02:29:03 +09003554 buf[0] = 0;
Mike McCormackefcc1ec2005-09-12 12:07:15 +00003555 if (component->ComponentId)
Aric Stewartc5a14432005-05-18 17:46:12 +00003556 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00003557 TRACE("From %s\n",debugstr_w(component->ComponentId));
3558 CLSIDFromString(component->ComponentId, &clsid);
Aric Stewartc5a14432005-05-18 17:46:12 +00003559 encode_base85_guid(&clsid,buf);
3560 TRACE("to %s\n",debugstr_w(buf));
3561 strcatW(data,buf);
3562 }
Aric Stewart6269f002005-01-17 13:40:39 +00003563 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00003564 if (feature->Feature_Parent)
Aric Stewart6269f002005-01-17 13:40:39 +00003565 {
3566 static const WCHAR sep[] = {'\2',0};
3567 strcatW(data,sep);
Mike McCormack1da28582005-08-22 14:09:17 +00003568 strcatW(data,feature->Feature_Parent);
Aric Stewart6269f002005-01-17 13:40:39 +00003569 }
3570
Mike McCormack4db02cd2005-09-15 14:58:38 +00003571 msi_reg_set_val_str( hkey, feature->Feature, data );
Mike McCormackee034ba2005-09-20 11:59:14 +00003572 msi_free(data);
Aric Stewart6269f002005-01-17 13:40:39 +00003573
Mike McCormack79ca56c2005-09-13 10:37:37 +00003574 size = 0;
3575 if (feature->Feature_Parent)
3576 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003577 if (!absent)
3578 {
Mike McCormack1da28582005-08-22 14:09:17 +00003579 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3580 (LPBYTE)feature->Feature_Parent,size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003581 }
3582 else
3583 {
Mike McCormack79ca56c2005-09-13 10:37:37 +00003584 size += 2*sizeof(WCHAR);
Mike McCormackee034ba2005-09-20 11:59:14 +00003585 data = msi_alloc(size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003586 data[0] = 0x6;
Mike McCormack79ca56c2005-09-13 10:37:37 +00003587 data[1] = 0;
3588 if (feature->Feature_Parent)
3589 strcpyW( &data[1], feature->Feature_Parent );
Mike McCormack1da28582005-08-22 14:09:17 +00003590 RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
Mike McCormack16466af2005-07-06 10:33:30 +00003591 (LPBYTE)data,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00003592 msi_free(data);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003593 }
Robert Shearmand2e48e02006-01-23 17:29:50 +01003594
3595 /* the UI chunk */
3596 uirow = MSI_CreateRecord( 1 );
3597 MSI_RecordSetStringW( uirow, 1, feature->Feature );
3598 ui_actiondata( package, szPublishFeatures, uirow);
3599 msiobj_release( &uirow->hdr );
3600 /* FIXME: call ui_progress? */
Aric Stewart6269f002005-01-17 13:40:39 +00003601 }
3602
Aric Stewart6269f002005-01-17 13:40:39 +00003603end:
Aric Stewart6269f002005-01-17 13:40:39 +00003604 RegCloseKey(hkey);
3605 RegCloseKey(hukey);
3606 return rc;
3607}
3608
Mike McCormack5f830692006-09-08 16:20:46 +09003609static UINT msi_get_local_package_name( LPWSTR path )
Mike McCormack61f24a42005-09-30 10:32:41 +00003610{
Mike McCormack5f830692006-09-08 16:20:46 +09003611 static const WCHAR szInstaller[] = {
3612 '\\','I','n','s','t','a','l','l','e','r','\\',0};
3613 static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3614 DWORD time, len, i;
3615 HANDLE handle;
Mike McCormack61f24a42005-09-30 10:32:41 +00003616
Mike McCormack5f830692006-09-08 16:20:46 +09003617 time = GetTickCount();
3618 GetWindowsDirectoryW( path, MAX_PATH );
3619 lstrcatW( path, szInstaller );
3620 CreateDirectoryW( path, NULL );
3621
3622 len = lstrlenW(path);
3623 for (i=0; i<0x10000; i++)
Mike McCormack61f24a42005-09-30 10:32:41 +00003624 {
Mike McCormack5f830692006-09-08 16:20:46 +09003625 snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3626 handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3627 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
Mike McCormack61f24a42005-09-30 10:32:41 +00003628 if (handle != INVALID_HANDLE_VALUE)
3629 {
3630 CloseHandle(handle);
3631 break;
3632 }
3633 if (GetLastError() != ERROR_FILE_EXISTS &&
3634 GetLastError() != ERROR_SHARING_VIOLATION)
Mike McCormack5f830692006-09-08 16:20:46 +09003635 return ERROR_FUNCTION_FAILED;
3636 }
Mike McCormack61f24a42005-09-30 10:32:41 +00003637
Mike McCormack5f830692006-09-08 16:20:46 +09003638 return ERROR_SUCCESS;
3639}
3640
3641static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3642{
3643 static const WCHAR szOriginalDatabase[] =
3644 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3645 WCHAR packagefile[MAX_PATH];
3646 LPWSTR msiFilePath;
3647 UINT r;
3648
3649 r = msi_get_local_package_name( packagefile );
3650 if (r != ERROR_SUCCESS)
3651 return r;
Mike McCormack61f24a42005-09-30 10:32:41 +00003652
3653 TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3654
3655 msiFilePath = msi_dup_property( package, szOriginalDatabase );
3656 r = CopyFileW( msiFilePath, packagefile, FALSE);
3657 msi_free( msiFilePath );
3658
3659 if (!r)
3660 {
Mike McCormackf1d46462006-10-05 13:41:22 +09003661 ERR("Unable to copy package (%s -> %s) (error %d)\n",
Mike McCormack61f24a42005-09-30 10:32:41 +00003662 debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3663 return ERROR_FUNCTION_FAILED;
3664 }
3665
3666 /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3667 msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3668 return ERROR_SUCCESS;
3669}
3670
Mike McCormackba293ee2005-10-27 12:08:16 +00003671static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3672{
3673 LPWSTR prop, val, key;
3674 static const LPCSTR propval[] = {
3675 "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3676 "ARPCONTACT", "Contact",
3677 "ARPCOMMENTS", "Comments",
3678 "ProductName", "DisplayName",
3679 "ProductVersion", "DisplayVersion",
3680 "ARPHELPLINK", "HelpLink",
3681 "ARPHELPTELEPHONE", "HelpTelephone",
3682 "ARPINSTALLLOCATION", "InstallLocation",
3683 "SourceDir", "InstallSource",
3684 "Manufacturer", "Publisher",
3685 "ARPREADME", "Readme",
3686 "ARPSIZE", "Size",
3687 "ARPURLINFOABOUT", "URLInfoAbout",
3688 "ARPURLUPDATEINFO", "URLUpdateInfo",
3689 NULL,
3690 };
3691 const LPCSTR *p = propval;
3692
3693 while( *p )
3694 {
3695 prop = strdupAtoW( *p++ );
3696 key = strdupAtoW( *p++ );
3697 val = msi_dup_property( package, prop );
3698 msi_reg_set_val_str( hkey, key, val );
3699 msi_free(val);
3700 msi_free(key);
3701 msi_free(prop);
3702 }
3703 return ERROR_SUCCESS;
3704}
3705
Aric Stewart2cae30b2005-01-19 19:07:40 +00003706static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3707{
Aric Stewart68b07492005-01-25 11:05:37 +00003708 HKEY hkey=0;
Aric Stewarte9db87b2005-06-17 21:25:41 +00003709 LPWSTR buffer = NULL;
Mike McCormackba293ee2005-10-27 12:08:16 +00003710 UINT rc;
Mike McCormack74f0de92005-09-29 10:32:39 +00003711 DWORD size, langid;
Mike McCormack4db02cd2005-09-15 14:58:38 +00003712 static const WCHAR szWindowsInstaller[] =
Mike McCormackba293ee2005-10-27 12:08:16 +00003713 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
Aric Stewart36a01502005-06-08 19:07:52 +00003714 static const WCHAR szUpgradeCode[] =
3715 {'U','p','g','r','a','d','e','C','o','d','e',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003716 static const WCHAR modpath_fmt[] =
Mike McCormackba293ee2005-10-27 12:08:16 +00003717 {'M','s','i','E','x','e','c','.','e','x','e',' ',
3718 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003719 static const WCHAR szModifyPath[] =
3720 {'M','o','d','i','f','y','P','a','t','h',0};
3721 static const WCHAR szUninstallString[] =
3722 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3723 static const WCHAR szEstimatedSize[] =
3724 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003725 static const WCHAR szProductLanguage[] =
3726 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3727 static const WCHAR szProductVersion[] =
3728 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
Aric Stewarte9db87b2005-06-17 21:25:41 +00003729
3730 SYSTEMTIME systime;
3731 static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
Aric Stewart36a01502005-06-08 19:07:52 +00003732 LPWSTR upgrade_code;
Mike McCormackba293ee2005-10-27 12:08:16 +00003733 WCHAR szDate[9];
Aric Stewart2cae30b2005-01-19 19:07:40 +00003734
Aric Stewartadaef112005-07-07 20:27:06 +00003735 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
Aric Stewart2cae30b2005-01-19 19:07:40 +00003736 if (rc != ERROR_SUCCESS)
Mike McCormackba293ee2005-10-27 12:08:16 +00003737 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003738
3739 /* dump all the info i can grab */
Mike McCormackb7270b82005-12-31 13:18:11 +01003740 /* FIXME: Flesh out more information */
Aric Stewart2cae30b2005-01-19 19:07:40 +00003741
Mike McCormackba293ee2005-10-27 12:08:16 +00003742 msi_write_uninstall_property_vals( package, hkey );
Aric Stewart2cae30b2005-01-19 19:07:40 +00003743
Mike McCormack4db02cd2005-09-15 14:58:38 +00003744 msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
Aric Stewart2cae30b2005-01-19 19:07:40 +00003745
Mike McCormack61f24a42005-09-30 10:32:41 +00003746 msi_make_package_local( package, hkey );
Aric Stewart36a01502005-06-08 19:07:52 +00003747
Aric Stewarte9db87b2005-06-17 21:25:41 +00003748 /* do ModifyPath and UninstallString */
3749 size = deformat_string(package,modpath_fmt,&buffer);
Mike McCormack16466af2005-07-06 10:33:30 +00003750 RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3751 RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00003752 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00003753
Mike McCormackb7270b82005-12-31 13:18:11 +01003754 /* FIXME: Write real Estimated Size when we have it */
Mike McCormack4db02cd2005-09-15 14:58:38 +00003755 msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
Aric Stewarte9db87b2005-06-17 21:25:41 +00003756
3757 GetLocalTime(&systime);
Mike McCormackba293ee2005-10-27 12:08:16 +00003758 sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3759 msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
Aric Stewarte9db87b2005-06-17 21:25:41 +00003760
Mike McCormack74f0de92005-09-29 10:32:39 +00003761 langid = msi_get_property_int( package, szProductLanguage, 0 );
3762 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
Aric Stewarte9db87b2005-06-17 21:25:41 +00003763
Mike McCormack062ad502005-09-15 15:04:08 +00003764 buffer = msi_dup_property( package, szProductVersion );
Aric Stewarte9db87b2005-06-17 21:25:41 +00003765 if (buffer)
3766 {
Mike McCormack230af9d2006-07-14 15:19:08 +09003767 DWORD verdword = msi_version_str_to_dword(buffer);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003768
3769 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3770 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3771 msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
Aric Stewarte9db87b2005-06-17 21:25:41 +00003772 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003773 msi_free(buffer);
Aric Stewarte9db87b2005-06-17 21:25:41 +00003774
Aric Stewart36a01502005-06-08 19:07:52 +00003775 /* Handle Upgrade Codes */
Mike McCormack062ad502005-09-15 15:04:08 +00003776 upgrade_code = msi_dup_property( package, szUpgradeCode );
Aric Stewart36a01502005-06-08 19:07:52 +00003777 if (upgrade_code)
3778 {
3779 HKEY hkey2;
3780 WCHAR squashed[33];
3781 MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
Aric Stewartadaef112005-07-07 20:27:06 +00003782 squash_guid(package->ProductCode,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003783 msi_reg_set_val_str( hkey2, squashed, NULL );
Aric Stewart36a01502005-06-08 19:07:52 +00003784 RegCloseKey(hkey2);
3785 MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
Aric Stewartadaef112005-07-07 20:27:06 +00003786 squash_guid(package->ProductCode,squashed);
Mike McCormack4db02cd2005-09-15 14:58:38 +00003787 msi_reg_set_val_str( hkey2, squashed, NULL );
Aric Stewart36a01502005-06-08 19:07:52 +00003788 RegCloseKey(hkey2);
3789
Mike McCormackee034ba2005-09-20 11:59:14 +00003790 msi_free(upgrade_code);
Aric Stewart36a01502005-06-08 19:07:52 +00003791 }
Aric Stewart2cae30b2005-01-19 19:07:40 +00003792
Aric Stewart2cae30b2005-01-19 19:07:40 +00003793 RegCloseKey(hkey);
Aric Stewart2cae30b2005-01-19 19:07:40 +00003794
Robert Shearmand2e48e02006-01-23 17:29:50 +01003795 /* FIXME: call ui_actiondata */
3796
Aric Stewart2cae30b2005-01-19 19:07:40 +00003797 return ERROR_SUCCESS;
3798}
3799
3800static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3801{
Mike McCormacka977b2c2005-11-03 09:56:29 +00003802 return execute_script(package,INSTALL_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00003803}
3804
3805static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3806{
Aric Stewart9cd707d2005-05-27 19:24:22 +00003807 UINT rc;
3808
Francois Gouget1ccf9442006-11-12 19:51:37 +01003809 /* turn off scheduling */
Aric Stewart9cd707d2005-05-27 19:24:22 +00003810 package->script->CurrentlyScripting= FALSE;
3811
Aric Stewart54c67dd2005-01-25 20:17:09 +00003812 /* first do the same as an InstallExecute */
Aric Stewart9cd707d2005-05-27 19:24:22 +00003813 rc = ACTION_InstallExecute(package);
3814 if (rc != ERROR_SUCCESS)
3815 return rc;
Aric Stewart54c67dd2005-01-25 20:17:09 +00003816
3817 /* then handle Commit Actions */
Aric Stewart9cd707d2005-05-27 19:24:22 +00003818 rc = execute_script(package,COMMIT_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00003819
Aric Stewart9cd707d2005-05-27 19:24:22 +00003820 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003821}
3822
3823static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3824{
3825 static const WCHAR RunOnce[] = {
3826 'S','o','f','t','w','a','r','e','\\',
3827 'M','i','c','r','o','s','o','f','t','\\',
3828 'W','i','n','d','o','w','s','\\',
3829 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00003830 'R','u','n','O','n','c','e',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00003831 static const WCHAR InstallRunOnce[] = {
3832 'S','o','f','t','w','a','r','e','\\',
3833 'M','i','c','r','o','s','o','f','t','\\',
3834 'W','i','n','d','o','w','s','\\',
3835 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3836 'I','n','s','t','a','l','l','e','r','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00003837 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00003838
3839 static const WCHAR msiexec_fmt[] = {
Juan Lang014ad3b2005-03-01 10:41:52 +00003840 '%','s',
Aric Stewart2cae30b2005-01-19 19:07:40 +00003841 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3842 '\"','%','s','\"',0};
3843 static const WCHAR install_fmt[] = {
3844 '/','I',' ','\"','%','s','\"',' ',
3845 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3846 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
Juan Lang014ad3b2005-03-01 10:41:52 +00003847 WCHAR buffer[256], sysdir[MAX_PATH];
Aric Stewartadaef112005-07-07 20:27:06 +00003848 HKEY hkey;
Mike McCormack4db02cd2005-09-15 14:58:38 +00003849 WCHAR squished_pc[100];
Aric Stewart2cae30b2005-01-19 19:07:40 +00003850
Aric Stewartadaef112005-07-07 20:27:06 +00003851 squash_guid(package->ProductCode,squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00003852
Juan Lang014ad3b2005-03-01 10:41:52 +00003853 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
Aric Stewart2cae30b2005-01-19 19:07:40 +00003854 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
Juan Lang014ad3b2005-03-01 10:41:52 +00003855 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3856 squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00003857
Mike McCormack4db02cd2005-09-15 14:58:38 +00003858 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00003859 RegCloseKey(hkey);
3860
3861 TRACE("Reboot command %s\n",debugstr_w(buffer));
3862
3863 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
Aric Stewartadaef112005-07-07 20:27:06 +00003864 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003865
Mike McCormack4db02cd2005-09-15 14:58:38 +00003866 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00003867 RegCloseKey(hkey);
3868
Aric Stewart68b07492005-01-25 11:05:37 +00003869 return ERROR_INSTALL_SUSPEND;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003870}
3871
Mike McCormackb9211182006-11-20 16:27:36 +09003872UINT msi_set_sourcedir_props(MSIPACKAGE *package)
3873{
3874 LPWSTR p, source;
3875 DWORD len;
3876
3877 p = strrchrW( package->PackagePath, '\\' );
3878 if (!p)
3879 return ERROR_SUCCESS;
3880
3881 len = p - package->PackagePath + 2;
3882 source = msi_alloc( len * sizeof(WCHAR) );
3883 lstrcpynW( source, package->PackagePath, len );
3884
3885 MSI_SetPropertyW( package, cszSourceDir, source );
3886 MSI_SetPropertyW( package, cszSOURCEDIR, source );
3887
3888 msi_free( source );
3889
3890 return ERROR_SUCCESS;
3891}
3892
James Hawkins563a50a2006-10-09 00:05:04 -07003893static UINT ACTION_ResolveSource(MSIPACKAGE* package)
Aric Stewart90c57392005-01-31 16:23:12 +00003894{
Mike McCormackb9211182006-11-20 16:27:36 +09003895 DWORD attrib;
Aric Stewart94d68182005-08-15 20:50:06 +00003896 UINT rc;
Mike McCormackfc564232006-11-20 16:17:03 +09003897
Aric Stewart90c57392005-01-31 16:23:12 +00003898 /*
Mike McCormackfc564232006-11-20 16:17:03 +09003899 * We are currently doing what should be done here in the top level Install
3900 * however for Administrative and uninstalls this step will be needed
Aric Stewart90c57392005-01-31 16:23:12 +00003901 */
Aric Stewart94d68182005-08-15 20:50:06 +00003902 if (!package->PackagePath)
3903 return ERROR_SUCCESS;
3904
Mike McCormackb9211182006-11-20 16:27:36 +09003905 msi_set_sourcedir_props(package);
James Hawkinsc5075432006-10-10 13:39:50 -07003906
Aric Stewart94d68182005-08-15 20:50:06 +00003907 attrib = GetFileAttributesW(package->PackagePath);
3908 if (attrib == INVALID_FILE_ATTRIBUTES)
3909 {
3910 LPWSTR prompt;
3911 LPWSTR msg;
3912 DWORD size = 0;
3913
3914 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
3915 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3916 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3917 if (rc == ERROR_MORE_DATA)
3918 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003919 prompt = msi_alloc(size * sizeof(WCHAR));
Aric Stewart94d68182005-08-15 20:50:06 +00003920 MsiSourceListGetInfoW(package->ProductCode, NULL,
3921 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3922 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3923 }
3924 else
3925 prompt = strdupW(package->PackagePath);
3926
3927 msg = generate_error_string(package,1302,1,prompt);
3928 while(attrib == INVALID_FILE_ATTRIBUTES)
3929 {
3930 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3931 if (rc == IDCANCEL)
3932 {
3933 rc = ERROR_INSTALL_USEREXIT;
3934 break;
3935 }
3936 attrib = GetFileAttributesW(package->PackagePath);
3937 }
Mike McCormackee034ba2005-09-20 11:59:14 +00003938 msi_free(prompt);
Aric Stewart94d68182005-08-15 20:50:06 +00003939 rc = ERROR_SUCCESS;
3940 }
3941 else
3942 return ERROR_SUCCESS;
3943
3944 return rc;
Aric Stewart90c57392005-01-31 16:23:12 +00003945}
3946
Aric Stewartc7e88e02005-02-10 17:09:44 +00003947static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3948{
Aric Stewartc7e88e02005-02-10 17:09:44 +00003949 HKEY hkey=0;
3950 LPWSTR buffer;
Aric Stewartc7e88e02005-02-10 17:09:44 +00003951 LPWSTR productid;
3952 UINT rc,i;
Aric Stewartc7e88e02005-02-10 17:09:44 +00003953
3954 static const WCHAR szPropKeys[][80] =
3955 {
Aric Stewart8e233e92005-03-01 11:45:19 +00003956 {'P','r','o','d','u','c','t','I','D',0},
3957 {'U','S','E','R','N','A','M','E',0},
3958 {'C','O','M','P','A','N','Y','N','A','M','E',0},
3959 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00003960 };
3961
3962 static const WCHAR szRegKeys[][80] =
3963 {
Aric Stewart8e233e92005-03-01 11:45:19 +00003964 {'P','r','o','d','u','c','t','I','D',0},
3965 {'R','e','g','O','w','n','e','r',0},
3966 {'R','e','g','C','o','m','p','a','n','y',0},
3967 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00003968 };
3969
Mike McCormack062ad502005-09-15 15:04:08 +00003970 productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
Aric Stewartc7e88e02005-02-10 17:09:44 +00003971 if (!productid)
3972 return ERROR_SUCCESS;
3973
Aric Stewartadaef112005-07-07 20:27:06 +00003974 rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
Aric Stewartc7e88e02005-02-10 17:09:44 +00003975 if (rc != ERROR_SUCCESS)
3976 goto end;
3977
Mike McCormack67189f92005-09-16 18:45:19 +00003978 for( i = 0; szPropKeys[i][0]; i++ )
Aric Stewartc7e88e02005-02-10 17:09:44 +00003979 {
Mike McCormack062ad502005-09-15 15:04:08 +00003980 buffer = msi_dup_property( package, szPropKeys[i] );
Mike McCormack4db02cd2005-09-15 14:58:38 +00003981 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00003982 msi_free( buffer );
Aric Stewartc7e88e02005-02-10 17:09:44 +00003983 }
3984
3985end:
Mike McCormackee034ba2005-09-20 11:59:14 +00003986 msi_free(productid);
Aric Stewartc7e88e02005-02-10 17:09:44 +00003987 RegCloseKey(hkey);
3988
Robert Shearmand2e48e02006-01-23 17:29:50 +01003989 /* FIXME: call ui_actiondata */
3990
Aric Stewartc7e88e02005-02-10 17:09:44 +00003991 return ERROR_SUCCESS;
3992}
3993
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003994
3995static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3996{
3997 UINT rc;
Aric Stewart25f1e752005-06-24 12:14:52 +00003998
Aric Stewartc9802932005-06-30 20:45:43 +00003999 package->script->InWhatSequence |= SEQUENCE_EXEC;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004000 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004001 return rc;
4002}
4003
Aric Stewart0af24872005-02-25 14:00:09 +00004004
Aric Stewart072c5e52005-04-20 12:50:05 +00004005static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
4006{
4007 MSIPACKAGE *package = (MSIPACKAGE*)param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00004008 LPCWSTR compgroupid=NULL;
4009 LPCWSTR feature=NULL;
4010 LPCWSTR text = NULL;
4011 LPCWSTR qualifier = NULL;
4012 LPCWSTR component = NULL;
Aric Stewart6f43c182005-05-26 12:24:28 +00004013 LPWSTR advertise = NULL;
4014 LPWSTR output = NULL;
Aric Stewart072c5e52005-04-20 12:50:05 +00004015 HKEY hkey;
4016 UINT rc = ERROR_SUCCESS;
Mike McCormack38d67a42005-08-22 09:15:23 +00004017 MSICOMPONENT *comp;
Aric Stewart072c5e52005-04-20 12:50:05 +00004018 DWORD sz = 0;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004019 MSIRECORD *uirow;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004020
Aric Stewart09b0aba2005-06-09 20:30:59 +00004021 component = MSI_RecordGetString(rec,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00004022 comp = get_loaded_component(package,component);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004023
Mike McCormackd693f462005-10-29 11:36:48 +00004024 if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
4025 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
4026 !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004027 {
4028 TRACE("Skipping: Component %s not scheduled for install\n",
4029 debugstr_w(component));
Aric Stewart6f43c182005-05-26 12:24:28 +00004030
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004031 return ERROR_SUCCESS;
4032 }
Aric Stewart072c5e52005-04-20 12:50:05 +00004033
Aric Stewart09b0aba2005-06-09 20:30:59 +00004034 compgroupid = MSI_RecordGetString(rec,1);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004035 qualifier = MSI_RecordGetString(rec,2);
Aric Stewart072c5e52005-04-20 12:50:05 +00004036
4037 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
4038 if (rc != ERROR_SUCCESS)
4039 goto end;
4040
Aric Stewart09b0aba2005-06-09 20:30:59 +00004041 text = MSI_RecordGetString(rec,4);
Aric Stewart09b0aba2005-06-09 20:30:59 +00004042 feature = MSI_RecordGetString(rec,5);
Aric Stewart072c5e52005-04-20 12:50:05 +00004043
Mike McCormack38d67a42005-08-22 09:15:23 +00004044 advertise = create_component_advertise_string(package, comp, feature);
Aric Stewart072c5e52005-04-20 12:50:05 +00004045
Aric Stewart6f43c182005-05-26 12:24:28 +00004046 sz = strlenW(advertise);
4047
Aric Stewart072c5e52005-04-20 12:50:05 +00004048 if (text)
4049 sz += lstrlenW(text);
Aric Stewart072c5e52005-04-20 12:50:05 +00004050
4051 sz+=3;
4052 sz *= sizeof(WCHAR);
4053
Mike McCormack3a940112006-04-19 02:29:03 +09004054 output = msi_alloc_zero(sz);
Aric Stewart6f43c182005-05-26 12:24:28 +00004055 strcpyW(output,advertise);
Mike McCormack470f23d2005-09-22 10:56:26 +00004056 msi_free(advertise);
Aric Stewart072c5e52005-04-20 12:50:05 +00004057
4058 if (text)
4059 strcatW(output,text);
4060
Mike McCormack4db02cd2005-09-15 14:58:38 +00004061 msi_reg_set_val_multi_str( hkey, qualifier, output );
Aric Stewart072c5e52005-04-20 12:50:05 +00004062
4063end:
4064 RegCloseKey(hkey);
Mike McCormackee034ba2005-09-20 11:59:14 +00004065 msi_free(output);
Robert Shearmand2e48e02006-01-23 17:29:50 +01004066
4067 /* the UI chunk */
4068 uirow = MSI_CreateRecord( 2 );
4069 MSI_RecordSetStringW( uirow, 1, compgroupid );
4070 MSI_RecordSetStringW( uirow, 2, qualifier);
4071 ui_actiondata( package, szPublishComponents, uirow);
4072 msiobj_release( &uirow->hdr );
4073 /* FIXME: call ui_progress? */
4074
Aric Stewart072c5e52005-04-20 12:50:05 +00004075 return rc;
4076}
4077
4078/*
4079 * At present I am ignorning the advertised components part of this and only
4080 * focusing on the qualified component sets
4081 */
4082static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4083{
4084 UINT rc;
4085 MSIQUERY * view;
4086 static const WCHAR ExecSeqQuery[] =
4087 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00004088 '`','P','u','b','l','i','s','h',
4089 'C','o','m','p','o','n','e','n','t','`',0};
Aric Stewart072c5e52005-04-20 12:50:05 +00004090
4091 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4092 if (rc != ERROR_SUCCESS)
4093 return ERROR_SUCCESS;
4094
4095 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4096 msiobj_release(&view->hdr);
4097
4098 return rc;
4099}
Mike McCormack202166c2005-09-23 10:09:18 +00004100
James Hawkins9bc12ad2006-10-19 15:49:54 -07004101static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4102{
4103 MSIPACKAGE *package = (MSIPACKAGE*)param;
4104 MSIRECORD *row;
4105 MSIFILE *file;
4106 SC_HANDLE hscm, service = NULL;
4107 LPCWSTR name, disp, comp, depends, pass;
4108 LPCWSTR load_order, serv_name, key;
4109 DWORD serv_type, start_type;
4110 DWORD err_control;
4111
4112 static const WCHAR query[] =
4113 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4114 '`','C','o','m','p','o','n','e','n','t','`',' ',
4115 'W','H','E','R','E',' ',
4116 '`','C','o','m','p','o','n','e','n','t','`',' ',
4117 '=','\'','%','s','\'',0};
4118
4119 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4120 if (!hscm)
4121 {
4122 ERR("Failed to open the SC Manager!\n");
4123 goto done;
4124 }
4125
4126 start_type = MSI_RecordGetInteger(rec, 5);
4127 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4128 goto done;
4129
4130 depends = MSI_RecordGetString(rec, 8);
4131 if (depends && *depends)
4132 FIXME("Dependency list unhandled!\n");
4133
4134 name = MSI_RecordGetString(rec, 2);
4135 disp = MSI_RecordGetString(rec, 3);
4136 serv_type = MSI_RecordGetInteger(rec, 4);
4137 err_control = MSI_RecordGetInteger(rec, 6);
4138 load_order = MSI_RecordGetString(rec, 7);
4139 serv_name = MSI_RecordGetString(rec, 9);
4140 pass = MSI_RecordGetString(rec, 10);
4141 comp = MSI_RecordGetString(rec, 12);
4142
4143 /* fetch the service path */
4144 row = MSI_QueryGetRecord(package->db, query, comp);
4145 if (!row)
4146 {
4147 ERR("Control query failed!\n");
4148 goto done;
4149 }
4150
4151 key = MSI_RecordGetString(row, 6);
4152 msiobj_release(&row->hdr);
4153
4154 file = get_loaded_file(package, key);
4155 if (!file)
4156 {
4157 ERR("Failed to load the service file\n");
4158 goto done;
4159 }
4160
4161 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4162 start_type, err_control, file->TargetPath,
4163 load_order, NULL, NULL, serv_name, pass);
4164 if (!service)
4165 {
4166 if (GetLastError() != ERROR_SERVICE_EXISTS)
4167 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4168 }
4169
4170done:
4171 CloseServiceHandle(service);
4172 CloseServiceHandle(hscm);
4173
4174 return ERROR_SUCCESS;
4175}
4176
4177static UINT ACTION_InstallServices( MSIPACKAGE *package )
4178{
4179 UINT rc;
4180 MSIQUERY * view;
4181 static const WCHAR ExecSeqQuery[] =
4182 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4183 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4184
4185 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4186 if (rc != ERROR_SUCCESS)
4187 return ERROR_SUCCESS;
4188
4189 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4190 msiobj_release(&view->hdr);
4191
4192 return rc;
4193}
4194
James Hawkins58bb3572006-12-01 13:22:59 -08004195/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
4196static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs)
4197{
4198 LPCWSTR *vector;
4199 LPWSTR p, q;
4200 DWORD sep_len;
4201
4202 static const WCHAR separator[] = {'[','~',']',0};
4203
4204 *numargs = 0;
4205 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
4206
4207 if (!args)
4208 return NULL;
4209
4210 vector = msi_alloc(sizeof(LPWSTR));
4211 if (!vector)
4212 return NULL;
4213
4214 p = args;
4215 do
4216 {
4217 (*numargs)++;
4218 vector[*numargs - 1] = p;
4219
4220 if ((q = strstrW(p, separator)))
4221 {
4222 *q = '\0';
4223
4224 vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
4225 if (!vector)
4226 return NULL;
4227
4228 p = q + sep_len;
4229 }
4230 } while (q);
4231
4232 return vector;
4233}
4234
4235static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component )
4236{
4237 MSICOMPONENT *comp;
4238
4239 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
4240 {
4241 if (!lstrcmpW(comp->Component, component))
4242 return comp;
4243 }
4244
4245 return NULL;
4246}
4247
4248static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
4249{
4250 MSIPACKAGE *package = (MSIPACKAGE *)param;
4251 MSICOMPONENT *comp;
4252 SC_HANDLE scm, service = NULL;
4253 LPCWSTR name, *vector = NULL;
4254 LPWSTR args;
4255 DWORD event, numargs;
4256 UINT r = ERROR_FUNCTION_FAILED;
4257
4258 comp = msi_find_component(package, MSI_RecordGetString(rec, 6));
4259 if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT)
4260 return ERROR_SUCCESS;
4261
4262 name = MSI_RecordGetString(rec, 2);
4263 event = MSI_RecordGetInteger(rec, 3);
4264 args = strdupW(MSI_RecordGetString(rec, 4));
4265
4266 if (!(event & msidbServiceControlEventStart))
4267 return ERROR_SUCCESS;
4268
4269 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
4270 if (!scm)
4271 {
4272 ERR("Failed to open the service control manager\n");
4273 goto done;
4274 }
4275
4276 service = OpenServiceW(scm, name, SERVICE_START);
4277 if (!service)
4278 {
4279 ERR("Failed to open service '%s'\n", debugstr_w(name));
4280 goto done;
4281 }
4282
4283 vector = msi_service_args_to_vector(name, args, &numargs);
4284
4285 if (!StartServiceW(service, numargs, vector))
4286 {
4287 ERR("Failed to start service '%s'\n", debugstr_w(name));
4288 goto done;
4289 }
4290
4291 r = ERROR_SUCCESS;
4292
4293done:
4294 CloseServiceHandle(service);
4295 CloseServiceHandle(scm);
4296
4297 msi_free(args);
4298 msi_free(vector);
4299 return r;
4300}
4301
4302static UINT ACTION_StartServices( MSIPACKAGE *package )
4303{
4304 UINT rc;
4305 MSIQUERY *view;
4306
4307 static const WCHAR query[] = {
4308 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4309 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4310
4311 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4312 if (rc != ERROR_SUCCESS)
4313 return ERROR_SUCCESS;
4314
4315 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
4316 msiobj_release(&view->hdr);
4317
4318 return rc;
4319}
4320
James Hawkinsd3bec322006-11-27 18:20:33 -08004321static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
4322{
4323 MSIFILE *file;
4324
4325 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
4326 {
4327 if (!lstrcmpW(file->File, filename))
4328 return file;
4329 }
4330
4331 return NULL;
4332}
4333
4334static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
4335{
4336 MSIPACKAGE *package = (MSIPACKAGE*)param;
4337 LPWSTR driver, driver_path, ptr;
4338 WCHAR outpath[MAX_PATH];
4339 MSIFILE *driver_file, *setup_file;
4340 LPCWSTR desc;
4341 DWORD len, usage;
4342 UINT r = ERROR_SUCCESS;
4343
4344 static const WCHAR driver_fmt[] = {
4345 'D','r','i','v','e','r','=','%','s',0};
4346 static const WCHAR setup_fmt[] = {
4347 'S','e','t','u','p','=','%','s',0};
4348 static const WCHAR usage_fmt[] = {
4349 'F','i','l','e','U','s','a','g','e','=','1',0};
4350
4351 desc = MSI_RecordGetString(rec, 3);
4352
4353 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
4354 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
4355
4356 if (!driver_file || !setup_file)
4357 {
4358 ERR("ODBC Driver entry not found!\n");
4359 return ERROR_FUNCTION_FAILED;
4360 }
4361
4362 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName) +
4363 lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName) +
4364 lstrlenW(usage_fmt) + 1;
4365 driver = msi_alloc(len * sizeof(WCHAR));
4366 if (!driver)
4367 return ERROR_OUTOFMEMORY;
4368
4369 ptr = driver;
4370 lstrcpyW(ptr, desc);
4371 ptr += lstrlenW(ptr) + 1;
4372
4373 sprintfW(ptr, driver_fmt, driver_file->FileName);
4374 ptr += lstrlenW(ptr) + 1;
4375
4376 sprintfW(ptr, setup_fmt, setup_file->FileName);
4377 ptr += lstrlenW(ptr) + 1;
4378
4379 lstrcpyW(ptr, usage_fmt);
4380 ptr += lstrlenW(ptr) + 1;
4381 *ptr = '\0';
4382
4383 driver_path = strdupW(driver_file->TargetPath);
4384 ptr = strrchrW(driver_path, '\\');
4385 if (ptr) *ptr = '\0';
4386
4387 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
4388 NULL, ODBC_INSTALL_COMPLETE, &usage))
4389 {
4390 ERR("Failed to install SQL driver!\n");
4391 r = ERROR_FUNCTION_FAILED;
4392 }
4393
4394 msi_free(driver);
4395 msi_free(driver_path);
4396
4397 return r;
4398}
4399
4400static UINT ACTION_InstallODBC( MSIPACKAGE *package )
4401{
4402 UINT rc;
4403 MSIQUERY *view;
4404
4405 static const WCHAR query[] = {
4406 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4407 'O','D','B','C','D','r','i','v','e','r',0 };
4408
4409 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4410 if (rc != ERROR_SUCCESS)
4411 return ERROR_SUCCESS;
4412
4413 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
4414 msiobj_release(&view->hdr);
4415
4416 return rc;
4417}
4418
Mike McCormack2586a092005-09-26 09:56:18 +00004419static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4420 LPCSTR action, LPCWSTR table )
Mike McCormack567f0312005-09-23 11:06:57 +00004421{
4422 static const WCHAR query[] = {
Mike McCormack2586a092005-09-26 09:56:18 +00004423 'S','E','L','E','C','T',' ','*',' ',
4424 'F','R','O','M',' ','`','%','s','`',0 };
Mike McCormack567f0312005-09-23 11:06:57 +00004425 MSIQUERY *view = NULL;
4426 DWORD count = 0;
Mike McCormack2586a092005-09-26 09:56:18 +00004427 UINT r;
Mike McCormack567f0312005-09-23 11:06:57 +00004428
Mike McCormack2586a092005-09-26 09:56:18 +00004429 r = MSI_OpenQuery( package->db, &view, query, table );
4430 if (r == ERROR_SUCCESS)
Mike McCormack567f0312005-09-23 11:06:57 +00004431 {
Mike McCormack2586a092005-09-26 09:56:18 +00004432 r = MSI_IterateRecords(view, &count, NULL, package);
Mike McCormack567f0312005-09-23 11:06:57 +00004433 msiobj_release(&view->hdr);
4434 }
4435
Mike McCormack2586a092005-09-26 09:56:18 +00004436 if (count)
Mike McCormackf1d46462006-10-05 13:41:22 +09004437 FIXME("%s -> %u ignored %s table values\n",
Mike McCormack2586a092005-09-26 09:56:18 +00004438 action, count, debugstr_w(table));
4439
Mike McCormack567f0312005-09-23 11:06:57 +00004440 return ERROR_SUCCESS;
4441}
Mike McCormack94fbe092005-09-23 17:21:10 +00004442
Mike McCormack55942702005-10-30 19:23:28 +00004443static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4444{
4445 TRACE("%p\n", package);
4446 return ERROR_SUCCESS;
4447}
4448
Mike McCormack2586a092005-09-26 09:56:18 +00004449static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
Mike McCormack94fbe092005-09-23 17:21:10 +00004450{
Mike McCormack2586a092005-09-26 09:56:18 +00004451 static const WCHAR table[] =
4452 {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4453 return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
Mike McCormack94fbe092005-09-23 17:21:10 +00004454}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00004455
Mike McCormack2586a092005-09-26 09:56:18 +00004456static UINT ACTION_MoveFiles( MSIPACKAGE *package )
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00004457{
Mike McCormack2586a092005-09-26 09:56:18 +00004458 static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4459 return msi_unimplemented_action_stub( package, "MoveFiles", table );
4460}
4461
4462static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4463{
4464 static const WCHAR table[] = { 'P','a','t','c','h',0 };
4465 return msi_unimplemented_action_stub( package, "PatchFiles", table );
4466}
4467
4468static UINT ACTION_BindImage( MSIPACKAGE *package )
4469{
4470 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4471 return msi_unimplemented_action_stub( package, "BindImage", table );
4472}
4473
4474static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4475{
4476 static const WCHAR table[] = {
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00004477 'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
Mike McCormack2586a092005-09-26 09:56:18 +00004478 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4479}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00004480
Mike McCormack2586a092005-09-26 09:56:18 +00004481static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4482{
4483 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4484 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4485}
4486
4487static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4488{
4489 static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4490 return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4491}
4492
Mike McCormack2586a092005-09-26 09:56:18 +00004493static UINT ACTION_StopServices( MSIPACKAGE *package )
4494{
4495 static const WCHAR table[] = {
4496 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4497 return msi_unimplemented_action_stub( package, "StopServices", table );
4498}
4499
4500static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4501{
4502 static const WCHAR table[] = {
4503 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4504 return msi_unimplemented_action_stub( package, "DeleteServices", table );
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00004505}
Mike McCormack3b955152005-09-28 18:10:44 +00004506
4507static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4508{
4509 static const WCHAR table[] = {
4510 'E','n','v','i','r','o','n','m','e','n','t',0 };
4511 return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4512}
4513
4514static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4515{
4516 static const WCHAR table[] = {
4517 'E','n','v','i','r','o','n','m','e','n','t',0 };
4518 return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4519}
4520
4521static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4522{
4523 static const WCHAR table[] = {
4524 'M','s','i','A','s','s','e','m','b','l','y',0 };
4525 return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4526}
4527
4528static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4529{
4530 static const WCHAR table[] = {
4531 'M','s','i','A','s','s','e','m','b','l','y',0 };
4532 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4533}
4534
4535static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4536{
4537 static const WCHAR table[] = { 'F','o','n','t',0 };
4538 return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4539}
4540
Mike McCormackf24a9e22005-12-31 13:14:23 +01004541static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4542{
4543 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4544 return msi_unimplemented_action_stub( package, "CCPSearch", table );
4545}
4546
4547static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4548{
4549 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4550 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4551}
4552
Mike McCormack88603662006-03-22 23:01:56 +09004553static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4554{
4555 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4556 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4557}
4558
4559static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4560{
4561 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4562 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4563}
4564
Dmitry Timoshkov1cdf5cd2006-11-29 18:03:14 +08004565static const struct _actions StandardActions[] = {
Mike McCormack55942702005-10-30 19:23:28 +00004566 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
Mike McCormack3b955152005-09-28 18:10:44 +00004567 { szAppSearch, ACTION_AppSearch },
4568 { szBindImage, ACTION_BindImage },
Mike McCormackf24a9e22005-12-31 13:14:23 +01004569 { szCCPSearch, ACTION_CCPSearch},
Mike McCormack3b955152005-09-28 18:10:44 +00004570 { szCostFinalize, ACTION_CostFinalize },
4571 { szCostInitialize, ACTION_CostInitialize },
4572 { szCreateFolders, ACTION_CreateFolders },
4573 { szCreateShortcuts, ACTION_CreateShortcuts },
4574 { szDeleteServices, ACTION_DeleteServices },
4575 { szDisableRollback, NULL},
4576 { szDuplicateFiles, ACTION_DuplicateFiles },
4577 { szExecuteAction, ACTION_ExecuteAction },
4578 { szFileCost, ACTION_FileCost },
4579 { szFindRelatedProducts, ACTION_FindRelatedProducts },
4580 { szForceReboot, ACTION_ForceReboot },
4581 { szInstallAdminPackage, NULL},
4582 { szInstallExecute, ACTION_InstallExecute },
4583 { szInstallExecuteAgain, ACTION_InstallExecute },
4584 { szInstallFiles, ACTION_InstallFiles},
4585 { szInstallFinalize, ACTION_InstallFinalize },
4586 { szInstallInitialize, ACTION_InstallInitialize },
4587 { szInstallSFPCatalogFile, NULL},
4588 { szInstallValidate, ACTION_InstallValidate },
4589 { szIsolateComponents, ACTION_IsolateComponents },
4590 { szLaunchConditions, ACTION_LaunchConditions },
4591 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4592 { szMoveFiles, ACTION_MoveFiles },
4593 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4594 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
James Hawkinsd3bec322006-11-27 18:20:33 -08004595 { szInstallODBC, ACTION_InstallODBC },
Mike McCormack3b955152005-09-28 18:10:44 +00004596 { szInstallServices, ACTION_InstallServices },
4597 { szPatchFiles, ACTION_PatchFiles },
4598 { szProcessComponents, ACTION_ProcessComponents },
4599 { szPublishComponents, ACTION_PublishComponents },
4600 { szPublishFeatures, ACTION_PublishFeatures },
4601 { szPublishProduct, ACTION_PublishProduct },
4602 { szRegisterClassInfo, ACTION_RegisterClassInfo },
Mike McCormack88603662006-03-22 23:01:56 +09004603 { szRegisterComPlus, ACTION_RegisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00004604 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4605 { szRegisterFonts, ACTION_RegisterFonts },
4606 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4607 { szRegisterProduct, ACTION_RegisterProduct },
4608 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4609 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4610 { szRegisterUser, ACTION_RegisterUser},
4611 { szRemoveDuplicateFiles, NULL},
4612 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4613 { szRemoveExistingProducts, NULL},
Mike McCormackfd4a2002005-11-02 11:42:56 +00004614 { szRemoveFiles, ACTION_RemoveFiles},
Mike McCormack3b955152005-09-28 18:10:44 +00004615 { szRemoveFolders, NULL},
4616 { szRemoveIniValues, ACTION_RemoveIniValues },
4617 { szRemoveODBC, NULL},
4618 { szRemoveRegistryValues, NULL},
4619 { szRemoveShortcuts, NULL},
4620 { szResolveSource, ACTION_ResolveSource},
Mike McCormackf24a9e22005-12-31 13:14:23 +01004621 { szRMCCPSearch, ACTION_RMCCPSearch},
Mike McCormack3b955152005-09-28 18:10:44 +00004622 { szScheduleReboot, NULL},
4623 { szSelfRegModules, ACTION_SelfRegModules },
4624 { szSelfUnregModules, ACTION_SelfUnregModules },
4625 { szSetODBCFolders, NULL},
4626 { szStartServices, ACTION_StartServices },
4627 { szStopServices, ACTION_StopServices },
4628 { szUnpublishComponents, NULL},
4629 { szUnpublishFeatures, NULL},
4630 { szUnregisterClassInfo, NULL},
Mike McCormack88603662006-03-22 23:01:56 +09004631 { szUnregisterComPlus, ACTION_UnregisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00004632 { szUnregisterExtensionInfo, NULL},
4633 { szUnregisterFonts, ACTION_UnregisterFonts },
4634 { szUnregisterMIMEInfo, NULL},
4635 { szUnregisterProgIdInfo, NULL},
4636 { szUnregisterTypeLibraries, NULL},
4637 { szValidateProductID, NULL},
4638 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4639 { szWriteIniValues, ACTION_WriteIniValues },
4640 { szWriteRegistryValues, ACTION_WriteRegistryValues},
4641 { NULL, NULL},
4642};