blob: c5354de13e7d54215add04902c486871694d218d [file] [log] [blame]
Aric Stewart401bd3f2004-06-28 20:34:35 +00001/*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
Aric Stewartc6689522005-06-17 20:56:55 +00004 * Copyright 2004,2005 Aric Stewart for CodeWeavers
Aric Stewart401bd3f2004-06-28 20:34:35 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Aric Stewart401bd3f2004-06-28 20:34:35 +000019 */
20
Aric Stewart401bd3f2004-06-28 20:34:35 +000021#include <stdarg.h>
Aric Stewart401bd3f2004-06-28 20:34:35 +000022
Francois Gouget486d0202004-10-07 03:06:48 +000023#define COBJMACROS
24
Aric Stewart401bd3f2004-06-28 20:34:35 +000025#include "windef.h"
26#include "winbase.h"
27#include "winerror.h"
28#include "winreg.h"
James Hawkins9bc12ad2006-10-19 15:49:54 -070029#include "winsvc.h"
James Hawkinsd3bec322006-11-27 18:20:33 -080030#include "odbcinst.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000031#include "wine/debug.h"
Aric Stewartb6bc6aa2005-02-24 12:47:43 +000032#include "msidefs.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000033#include "msipriv.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000034#include "winuser.h"
35#include "shlobj.h"
James Hawkinsbfe07d12008-04-30 04:22:46 -050036#include "objbase.h"
37#include "mscoree.h"
38#include "fusion.h"
39#include "shlwapi.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000040#include "wine/unicode.h"
Steven Edwards98efef12005-04-11 16:10:33 +000041#include "winver.h"
Aric Stewart401bd3f2004-06-28 20:34:35 +000042
Aric Stewartbd1bbc12005-01-03 20:00:13 +000043#define REG_PROGRESS_VALUE 13200
44#define COMPONENT_PROGRESS_VALUE 24000
Aric Stewart401bd3f2004-06-28 20:34:35 +000045
Aric Stewart401bd3f2004-06-28 20:34:35 +000046WINE_DEFAULT_DEBUG_CHANNEL(msi);
47
48/*
Aric Stewart401bd3f2004-06-28 20:34:35 +000049 * consts and values used
50 */
Juan Lang014ad3b2005-03-01 10:41:52 +000051static const WCHAR c_colon[] = {'C',':','\\',0};
Aric Stewartc6689522005-06-17 20:56:55 +000052
Mike McCormack9ba8ba32005-10-30 19:04:26 +000053static const WCHAR szCreateFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000054 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000055static const WCHAR szCostFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000056 {'C','o','s','t','F','i','n','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000057static const WCHAR szWriteRegistryValues[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020058 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000059static const WCHAR szCostInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000060 {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000061static const WCHAR szFileCost[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000062 {'F','i','l','e','C','o','s','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000063static const WCHAR szInstallInitialize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000064 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000065static const WCHAR szInstallValidate[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000066 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000067static const WCHAR szLaunchConditions[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000068 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000069static const WCHAR szProcessComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000070 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000071static const WCHAR szRegisterTypeLibraries[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020072 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000073static const WCHAR szCreateShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000074 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000075static const WCHAR szPublishProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000076 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000077static const WCHAR szWriteIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000078 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000079static const WCHAR szSelfRegModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000080 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000081static const WCHAR szPublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000082 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000083static const WCHAR szRegisterProduct[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000084 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000085static const WCHAR szInstallExecute[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000086 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000087static const WCHAR szInstallExecuteAgain[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020088 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000089static const WCHAR szInstallFinalize[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000090 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000091static const WCHAR szForceReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000092 {'F','o','r','c','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000093static const WCHAR szResolveSource[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000094 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000095static const WCHAR szAllocateRegistrySpace[] =
Hans Leidekker843382f2009-10-15 12:46:27 +020096 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000097static const WCHAR szBindImage[] =
Aric Stewart8e233e92005-03-01 11:45:19 +000098 {'B','i','n','d','I','m','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +000099static const WCHAR szDeleteServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000100 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000101static const WCHAR szDisableRollback[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000102 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000103static const WCHAR szExecuteAction[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000104 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000105static const WCHAR szInstallAdminPackage[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200106 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000107static const WCHAR szInstallSFPCatalogFile[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200108 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000109static const WCHAR szIsolateComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000110 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200111static const WCHAR szMigrateFeatureStates[] =
112 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000113static const WCHAR szMsiPublishAssemblies[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200114 {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000115static const WCHAR szMsiUnpublishAssemblies[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200116 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000117static const WCHAR szInstallODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000118 {'I','n','s','t','a','l','l','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000119static const WCHAR szInstallServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000120 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
Hans Leidekker843382f2009-10-15 12:46:27 +0200121static const WCHAR szPatchFiles[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000122 {'P','a','t','c','h','F','i','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000123static const WCHAR szPublishComponents[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000124 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000125static const WCHAR szRegisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000126 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000127static const WCHAR szRegisterUser[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000128 {'R','e','g','i','s','t','e','r','U','s','e','r',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000129static const WCHAR szRemoveEnvironmentStrings[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200130 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
131static const WCHAR szRemoveExistingProducts[] =
132 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000133static const WCHAR szRemoveFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000134 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000135static const WCHAR szRemoveIniValues[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000136 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000137static const WCHAR szRemoveODBC[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000138 {'R','e','m','o','v','e','O','D','B','C',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000139static const WCHAR szRemoveRegistryValues[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200140 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000141static const WCHAR szRemoveShortcuts[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000142 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000143static const WCHAR szRMCCPSearch[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000144 {'R','M','C','C','P','S','e','a','r','c','h',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000145static const WCHAR szScheduleReboot[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000146 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000147static const WCHAR szSelfUnregModules[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000148 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000149static const WCHAR szSetODBCFolders[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000150 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000151static const WCHAR szStartServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000152 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000153static const WCHAR szStopServices[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000154 {'S','t','o','p','S','e','r','v','i','c','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000155static const WCHAR szUnpublishComponents[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200156 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000157static const WCHAR szUnpublishFeatures[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000158 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000159static const WCHAR szUnregisterComPlus[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000160 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000161static const WCHAR szUnregisterTypeLibraries[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200162 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
Mike McCormack9ba8ba32005-10-30 19:04:26 +0000163static const WCHAR szValidateProductID[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000164 {'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 +0000165static const WCHAR szWriteEnvironmentStrings[] =
Hans Leidekker843382f2009-10-15 12:46:27 +0200166 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
Aric Stewart90c57392005-01-31 16:23:12 +0000167
Aric Stewart2703d712005-06-20 15:33:10 +0000168/********************************************************
169 * helper functions
170 ********************************************************/
171
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000172static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
Aric Stewartd2c395a2004-07-06 18:48:15 +0000173{
Aric Stewartd2c395a2004-07-06 18:48:15 +0000174 static const WCHAR Query_t[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000175 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000176 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
177 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=',
178 ' ','\'','%','s','\'',0};
Robert Shearmand679bc52006-01-23 17:30:31 +0100179 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000180
Mike McCormack0b352c72005-06-02 10:29:57 +0000181 row = MSI_QueryGetRecord( package->db, Query_t, action );
182 if (!row)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000183 return;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000184 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
185 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000186}
187
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000188static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
Aric Stewartd2c395a2004-07-06 18:48:15 +0000189 UINT rc)
190{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000191 MSIRECORD * row;
Aric Stewartd2c395a2004-07-06 18:48:15 +0000192 static const WCHAR template_s[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000193 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
194 '%','s', '.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000195 static const WCHAR template_e[]=
Aric Stewart8e233e92005-03-01 11:45:19 +0000196 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
197 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
198 '%','i','.',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000199 static const WCHAR format[] =
Aric Stewart8e233e92005-03-01 11:45:19 +0000200 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
Aric Stewartd2c395a2004-07-06 18:48:15 +0000201 WCHAR message[1024];
202 WCHAR timet[0x100];
203
204 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
205 if (start)
206 sprintfW(message,template_s,timet,action);
207 else
208 sprintfW(message,template_e,timet,action,rc);
209
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000210 row = MSI_CreateRecord(1);
211 MSI_RecordSetStringW(row,1,message);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000212
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000213 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
214 msiobj_release(&row->hdr);
Aric Stewartd2c395a2004-07-06 18:48:15 +0000215}
216
James Hawkinsca71e5a2008-10-30 04:03:07 -0500217UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
218 BOOL preserve_case )
Mike McCormacke3452222005-09-28 15:12:32 +0000219{
220 LPCWSTR ptr,ptr2;
221 BOOL quote;
222 DWORD len;
223 LPWSTR prop = NULL, val = NULL;
224
225 if (!szCommandLine)
226 return ERROR_SUCCESS;
227
228 ptr = szCommandLine;
229
230 while (*ptr)
231 {
232 if (*ptr==' ')
233 {
234 ptr++;
235 continue;
236 }
237
238 TRACE("Looking at %s\n",debugstr_w(ptr));
239
240 ptr2 = strchrW(ptr,'=');
241 if (!ptr2)
242 {
243 ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
244 break;
245 }
246
247 quote = FALSE;
248
249 len = ptr2-ptr;
250 prop = msi_alloc((len+1)*sizeof(WCHAR));
251 memcpy(prop,ptr,len*sizeof(WCHAR));
252 prop[len]=0;
James Hawkinsca71e5a2008-10-30 04:03:07 -0500253
254 if (!preserve_case)
255 struprW(prop);
256
Mike McCormacke3452222005-09-28 15:12:32 +0000257 ptr2++;
258
259 len = 0;
260 ptr = ptr2;
261 while (*ptr && (quote || (!quote && *ptr!=' ')))
262 {
263 if (*ptr == '"')
264 quote = !quote;
265 ptr++;
266 len++;
267 }
268
269 if (*ptr2=='"')
270 {
271 ptr2++;
272 len -= 2;
273 }
274 val = msi_alloc((len+1)*sizeof(WCHAR));
275 memcpy(val,ptr2,len*sizeof(WCHAR));
276 val[len] = 0;
277
278 if (lstrlenW(prop) > 0)
279 {
Hans Leidekkere31ee692010-04-21 11:38:40 +0200280 UINT r = msi_set_property( package->db, prop, val );
Hans Leidekker44b79832010-04-21 11:38:17 +0200281
Mike McCormacke3452222005-09-28 15:12:32 +0000282 TRACE("Found commandline property (%s) = (%s)\n",
283 debugstr_w(prop), debugstr_w(val));
Hans Leidekker44b79832010-04-21 11:38:17 +0200284
285 if (r == ERROR_SUCCESS && !strcmpW( prop, cszSourceDir ))
286 msi_reset_folders( package, TRUE );
Mike McCormacke3452222005-09-28 15:12:32 +0000287 }
288 msi_free(val);
289 msi_free(prop);
290 }
291
292 return ERROR_SUCCESS;
293}
294
Mike McCormack965a72a2005-10-26 12:06:21 +0000295
296static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
297{
Andrew Talbot2e372c02006-09-17 08:52:49 +0100298 LPCWSTR pc;
Mike McCormack965a72a2005-10-26 12:06:21 +0000299 LPWSTR p, *ret = NULL;
300 UINT count = 0;
301
302 if (!str)
303 return ret;
304
305 /* count the number of substrings */
Andrew Talbot2e372c02006-09-17 08:52:49 +0100306 for ( pc = str, count = 0; pc; count++ )
Mike McCormack965a72a2005-10-26 12:06:21 +0000307 {
Andrew Talbot2e372c02006-09-17 08:52:49 +0100308 pc = strchrW( pc, sep );
309 if (pc)
310 pc++;
Mike McCormack965a72a2005-10-26 12:06:21 +0000311 }
312
313 /* allocate space for an array of substring pointers and the substrings */
314 ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
315 (lstrlenW(str)+1) * sizeof(WCHAR) );
316 if (!ret)
317 return ret;
318
319 /* copy the string and set the pointers */
320 p = (LPWSTR) &ret[count+1];
321 lstrcpyW( p, str );
322 for( count = 0; (ret[count] = p); count++ )
323 {
324 p = strchrW( p, sep );
325 if (p)
326 *p++ = 0;
327 }
328
329 return ret;
330}
331
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900332static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
333{
Hans Leidekker86af8762009-03-24 10:26:42 +0100334 static const WCHAR szSystemLanguageID[] =
335 { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
336
337 LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
338 UINT ret = ERROR_FUNCTION_FAILED;
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900339
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200340 prod_code = msi_dup_property( package->db, szProductCode );
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900341 patch_product = msi_get_suminfo_product( patch );
342
343 TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
344
345 if ( strstrW( patch_product, prod_code ) )
Hans Leidekker86af8762009-03-24 10:26:42 +0100346 {
Hans Leidekker86af8762009-03-24 10:26:42 +0100347 MSISUMMARYINFO *si;
348 const WCHAR *p;
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900349
Hans Leidekker86af8762009-03-24 10:26:42 +0100350 si = MSI_GetSummaryInformationW( patch, 0 );
351 if (!si)
352 {
353 ERR("no summary information!\n");
354 goto end;
355 }
356
357 template = msi_suminfo_dup_string( si, PID_TEMPLATE );
358 if (!template)
359 {
360 ERR("no template property!\n");
361 msiobj_release( &si->hdr );
362 goto end;
363 }
364
365 if (!template[0])
366 {
367 ret = ERROR_SUCCESS;
368 msiobj_release( &si->hdr );
369 goto end;
370 }
371
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200372 langid = msi_dup_property( package->db, szSystemLanguageID );
Hans Leidekker86af8762009-03-24 10:26:42 +0100373 if (!langid)
374 {
375 msiobj_release( &si->hdr );
376 goto end;
377 }
378
379 p = strchrW( template, ';' );
Hans Leidekker843382f2009-10-15 12:46:27 +0200380 if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
Hans Leidekker86af8762009-03-24 10:26:42 +0100381 {
382 TRACE("applicable transform\n");
383 ret = ERROR_SUCCESS;
384 }
385
386 /* FIXME: check platform */
387
388 msiobj_release( &si->hdr );
389 }
390
391end:
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900392 msi_free( patch_product );
393 msi_free( prod_code );
Hans Leidekker86af8762009-03-24 10:26:42 +0100394 msi_free( template );
395 msi_free( langid );
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900396
397 return ret;
398}
399
Mike McCormack965a72a2005-10-26 12:06:21 +0000400static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
401 MSIDATABASE *patch_db, LPCWSTR name )
402{
403 UINT ret = ERROR_FUNCTION_FAILED;
404 IStorage *stg = NULL;
405 HRESULT r;
406
407 TRACE("%p %s\n", package, debugstr_w(name) );
408
409 if (*name++ != ':')
410 {
411 ERR("expected a colon in %s\n", debugstr_w(name));
412 return ERROR_FUNCTION_FAILED;
413 }
414
415 r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
416 if (SUCCEEDED(r))
417 {
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900418 ret = msi_check_transform_applicable( package, stg );
419 if (ret == ERROR_SUCCESS)
420 msi_table_apply_transform( package->db, stg );
421 else
422 TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
Mike McCormack965a72a2005-10-26 12:06:21 +0000423 IStorage_Release( stg );
Mike McCormack965a72a2005-10-26 12:06:21 +0000424 }
425 else
426 ERR("failed to open substorage %s\n", debugstr_w(name));
427
Mike McCormack0d7dc8f2006-10-24 01:12:13 +0900428 return ERROR_SUCCESS;
Mike McCormack965a72a2005-10-26 12:06:21 +0000429}
430
Hans Leidekker05e9a1f2009-09-02 11:44:17 +0200431UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
Mike McCormack965a72a2005-10-26 12:06:21 +0000432{
James Hawkins261e1172007-06-15 14:12:13 -0700433 LPWSTR guid_list, *guids, product_code;
Mike McCormack965a72a2005-10-26 12:06:21 +0000434 UINT i, ret = ERROR_FUNCTION_FAILED;
435
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200436 product_code = msi_dup_property( package->db, szProductCode );
James Hawkins261e1172007-06-15 14:12:13 -0700437 if (!product_code)
Mike McCormack965a72a2005-10-26 12:06:21 +0000438 {
James Hawkins261e1172007-06-15 14:12:13 -0700439 /* FIXME: the property ProductCode should be written into the DB somewhere */
440 ERR("no product code to check\n");
Mike McCormack965a72a2005-10-26 12:06:21 +0000441 return ERROR_SUCCESS;
442 }
443
444 guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
445 guids = msi_split_string( guid_list, ';' );
446 for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
447 {
James Hawkins261e1172007-06-15 14:12:13 -0700448 if (!lstrcmpW( guids[i], product_code ))
Mike McCormack965a72a2005-10-26 12:06:21 +0000449 ret = ERROR_SUCCESS;
450 }
451 msi_free( guids );
452 msi_free( guid_list );
James Hawkins261e1172007-06-15 14:12:13 -0700453 msi_free( product_code );
Mike McCormack965a72a2005-10-26 12:06:21 +0000454
455 return ret;
456}
457
James Hawkinsc059ceb2008-12-14 21:07:28 -0600458static UINT msi_set_media_source_prop(MSIPACKAGE *package)
459{
460 MSIQUERY *view;
461 MSIRECORD *rec = NULL;
462 LPWSTR patch;
463 LPCWSTR prop;
464 UINT r;
465
James Hawkinsc059ceb2008-12-14 21:07:28 -0600466 static const WCHAR query[] = {'S','E','L','E','C','T',' ',
467 '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
468 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
469 '`','S','o','u','r','c','e','`',' ','I','S',' ',
470 'N','O','T',' ','N','U','L','L',0};
471
472 r = MSI_DatabaseOpenViewW(package->db, query, &view);
473 if (r != ERROR_SUCCESS)
474 return r;
475
476 r = MSI_ViewExecute(view, 0);
477 if (r != ERROR_SUCCESS)
478 goto done;
479
480 if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
481 {
482 prop = MSI_RecordGetString(rec, 1);
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200483 patch = msi_dup_property(package->db, szPatch);
Hans Leidekkere31ee692010-04-21 11:38:40 +0200484 msi_set_property(package->db, prop, patch);
James Hawkinsc059ceb2008-12-14 21:07:28 -0600485 msi_free(patch);
486 }
487
488done:
489 if (rec) msiobj_release(&rec->hdr);
490 msiobj_release(&view->hdr);
491
492 return r;
493}
494
Hans Leidekker82d7b042010-05-05 14:37:55 +0200495UINT msi_parse_patch_summary( MSISUMMARYINFO *si, MSIPATCHINFO **patch )
Mike McCormack965a72a2005-10-26 12:06:21 +0000496{
Hans Leidekker162780d2010-04-29 09:39:22 +0200497 MSIPATCHINFO *pi;
Hans Leidekker33299fa2010-04-13 11:16:17 +0200498 UINT r = ERROR_SUCCESS;
Mike McCormack965a72a2005-10-26 12:06:21 +0000499
Hans Leidekker23eabb42010-05-04 09:06:42 +0200500 pi = msi_alloc_zero( sizeof(MSIPATCHINFO) );
Hans Leidekker162780d2010-04-29 09:39:22 +0200501 if (!pi)
502 return ERROR_OUTOFMEMORY;
Mike McCormack965a72a2005-10-26 12:06:21 +0000503
Hans Leidekker162780d2010-04-29 09:39:22 +0200504 pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER );
505 if (!pi->patchcode)
James Hawkins01eb9302008-12-14 21:07:23 -0600506 {
Hans Leidekker162780d2010-04-29 09:39:22 +0200507 msi_free( pi );
James Hawkins01eb9302008-12-14 21:07:23 -0600508 return ERROR_OUTOFMEMORY;
Hans Leidekkerbcc0ad92010-04-13 11:15:55 +0200509 }
James Hawkins01eb9302008-12-14 21:07:23 -0600510
Hans Leidekker162780d2010-04-29 09:39:22 +0200511 pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
512 if (!pi->transforms)
Hans Leidekkerbcc0ad92010-04-13 11:15:55 +0200513 {
Hans Leidekker162780d2010-04-29 09:39:22 +0200514 msi_free( pi->patchcode );
515 msi_free( pi );
James Hawkins01eb9302008-12-14 21:07:23 -0600516 return ERROR_OUTOFMEMORY;
Hans Leidekkerbcc0ad92010-04-13 11:15:55 +0200517 }
Mike McCormack965a72a2005-10-26 12:06:21 +0000518
Hans Leidekker162780d2010-04-29 09:39:22 +0200519 *patch = pi;
Mike McCormack965a72a2005-10-26 12:06:21 +0000520 return r;
521}
522
Hans Leidekker82d7b042010-05-05 14:37:55 +0200523UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
524{
525 UINT i, r = ERROR_SUCCESS;
526 WCHAR **substorage;
527
528 /* apply substorage transforms */
529 substorage = msi_split_string( patch->transforms, ';' );
530 for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
531 r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
532
533 msi_free( substorage );
534 if (r != ERROR_SUCCESS)
535 return r;
536
537 msi_set_media_source_prop( package );
538
539 /*
540 * There might be a CAB file in the patch package,
541 * so append it to the list of storages to search for streams.
542 */
543 append_storage_to_db( package->db, patch_db->storage );
544
545 list_add_tail( &package->patches, &patch->entry );
546 return ERROR_SUCCESS;
547}
548
Mike McCormack965a72a2005-10-26 12:06:21 +0000549static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
550{
Hans Leidekker23eabb42010-05-04 09:06:42 +0200551 static const WCHAR dotmsp[] = {'.','m','s','p',0};
Mike McCormack965a72a2005-10-26 12:06:21 +0000552 MSIDATABASE *patch_db = NULL;
Hans Leidekker23eabb42010-05-04 09:06:42 +0200553 WCHAR localfile[MAX_PATH];
Hans Leidekker162780d2010-04-29 09:39:22 +0200554 MSISUMMARYINFO *si;
Hans Leidekker23eabb42010-05-04 09:06:42 +0200555 MSIPATCHINFO *patch = NULL;
Hans Leidekker82d7b042010-05-05 14:37:55 +0200556 UINT r = ERROR_SUCCESS;
Mike McCormack965a72a2005-10-26 12:06:21 +0000557
558 TRACE("%p %s\n", package, debugstr_w( file ) );
559
Hans Leidekkerc6f281f2010-04-29 09:38:54 +0200560 r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
Mike McCormack965a72a2005-10-26 12:06:21 +0000561 if ( r != ERROR_SUCCESS )
562 {
563 ERR("failed to open patch collection %s\n", debugstr_w( file ) );
564 return r;
565 }
566
Hans Leidekker162780d2010-04-29 09:39:22 +0200567 si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
568 if (!si)
569 {
570 msiobj_release( &patch_db->hdr );
571 return ERROR_FUNCTION_FAILED;
572 }
573
574 r = msi_check_patch_applicable( package, si );
575 if (r != ERROR_SUCCESS)
576 {
577 TRACE("patch not applicable\n");
Hans Leidekker23eabb42010-05-04 09:06:42 +0200578 r = ERROR_SUCCESS;
579 goto done;
Hans Leidekker162780d2010-04-29 09:39:22 +0200580 }
581
582 r = msi_parse_patch_summary( si, &patch );
583 if ( r != ERROR_SUCCESS )
Hans Leidekker23eabb42010-05-04 09:06:42 +0200584 goto done;
585
586 r = msi_get_local_package_name( localfile, dotmsp );
587 if ( r != ERROR_SUCCESS )
588 goto done;
589
590 TRACE("copying to local package %s\n", debugstr_w(localfile));
591
592 if (!CopyFileW( file, localfile, FALSE ))
Hans Leidekker162780d2010-04-29 09:39:22 +0200593 {
Hans Leidekker23eabb42010-05-04 09:06:42 +0200594 ERR("Unable to copy package (%s -> %s) (error %u)\n",
595 debugstr_w(file), debugstr_w(localfile), GetLastError());
596 r = GetLastError();
597 goto done;
Hans Leidekker162780d2010-04-29 09:39:22 +0200598 }
Hans Leidekker23eabb42010-05-04 09:06:42 +0200599 patch->localfile = strdupW( localfile );
Mike McCormack9a4ba8c2006-11-01 15:09:23 +0900600
Hans Leidekker82d7b042010-05-05 14:37:55 +0200601 r = msi_apply_patch_db( package, patch_db, patch );
602 if ( r != ERROR_SUCCESS )
603 WARN("patch failed to apply %u\n", r);
Hans Leidekker162780d2010-04-29 09:39:22 +0200604
Hans Leidekker23eabb42010-05-04 09:06:42 +0200605done:
Hans Leidekker162780d2010-04-29 09:39:22 +0200606 msiobj_release( &si->hdr );
Mike McCormack965a72a2005-10-26 12:06:21 +0000607 msiobj_release( &patch_db->hdr );
Hans Leidekker23eabb42010-05-04 09:06:42 +0200608 if (patch && r != ERROR_SUCCESS)
609 {
610 if (patch->localfile)
611 DeleteFileW( patch->localfile );
Mike McCormack965a72a2005-10-26 12:06:21 +0000612
Hans Leidekker23eabb42010-05-04 09:06:42 +0200613 msi_free( patch->patchcode );
614 msi_free( patch->transforms );
615 msi_free( patch->localfile );
616 msi_free( patch );
617 }
618 return r;
Mike McCormack965a72a2005-10-26 12:06:21 +0000619}
620
621/* get the PATCH property, and apply all the patches it specifies */
622static UINT msi_apply_patches( MSIPACKAGE *package )
623{
Mike McCormack965a72a2005-10-26 12:06:21 +0000624 LPWSTR patch_list, *patches;
625 UINT i, r = ERROR_SUCCESS;
626
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200627 patch_list = msi_dup_property( package->db, szPatch );
Mike McCormack965a72a2005-10-26 12:06:21 +0000628
629 TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
630
631 patches = msi_split_string( patch_list, ';' );
632 for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
633 r = msi_apply_patch_package( package, patches[i] );
634
635 msi_free( patches );
636 msi_free( patch_list );
637
638 return r;
639}
640
Mike McCormacke534e772006-01-04 14:51:25 +0100641static UINT msi_apply_transforms( MSIPACKAGE *package )
642{
643 static const WCHAR szTransforms[] = {
644 'T','R','A','N','S','F','O','R','M','S',0 };
645 LPWSTR xform_list, *xforms;
646 UINT i, r = ERROR_SUCCESS;
647
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200648 xform_list = msi_dup_property( package->db, szTransforms );
Mike McCormacke534e772006-01-04 14:51:25 +0100649 xforms = msi_split_string( xform_list, ';' );
650
651 for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
652 {
653 if (xforms[i][0] == ':')
James Hawkins776a7d72008-03-10 23:03:50 -0500654 r = msi_apply_substorage_transform( package, package->db, xforms[i] );
Mike McCormacke534e772006-01-04 14:51:25 +0100655 else
656 r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
657 }
658
659 msi_free( xforms );
660 msi_free( xform_list );
661
662 return r;
663}
664
James Hawkins4439e0b2008-02-29 23:29:43 -0600665static BOOL ui_sequence_exists( MSIPACKAGE *package )
James Hawkins6da80412007-04-15 03:10:58 -0500666{
667 MSIQUERY *view;
668 UINT rc;
669
670 static const WCHAR ExecSeqQuery [] =
671 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
672 '`','I','n','s','t','a','l','l',
673 'U','I','S','e','q','u','e','n','c','e','`',
674 ' ','W','H','E','R','E',' ',
675 '`','S','e','q','u','e','n','c','e','`',' ',
676 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
677 '`','S','e','q','u','e','n','c','e','`',0};
678
679 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
680 if (rc == ERROR_SUCCESS)
681 {
682 msiobj_release(&view->hdr);
683 return TRUE;
684 }
685
686 return FALSE;
687}
688
James Hawkinsc777d302008-01-05 13:45:13 -0700689static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
690{
James Hawkinsc777d302008-01-05 13:45:13 -0700691 LPWSTR source, check;
James Hawkinsc777d302008-01-05 13:45:13 -0700692
Hans Leidekkerdd305c32010-05-11 14:05:32 +0200693 if (msi_get_property_int( package->db, szInstalled, 0 ))
James Hawkins062070b2008-01-05 13:46:39 -0700694 {
Hans Leidekkerdd305c32010-05-11 14:05:32 +0200695 HKEY hkey;
696
697 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
698 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW );
699 RegCloseKey( hkey );
700 }
701 else
702 {
703 LPWSTR p, db;
704 DWORD len;
705
706 db = msi_dup_property( package->db, szOriginalDatabase );
707 if (!db)
708 return ERROR_OUTOFMEMORY;
709
710 p = strrchrW( db, '\\' );
James Hawkins18648762008-01-05 13:47:14 -0700711 if (!p)
712 {
Hans Leidekkerdd305c32010-05-11 14:05:32 +0200713 p = strrchrW( db, '/' );
714 if (!p)
715 {
716 msi_free(db);
717 return ERROR_SUCCESS;
718 }
James Hawkins18648762008-01-05 13:47:14 -0700719 }
James Hawkins062070b2008-01-05 13:46:39 -0700720
Hans Leidekkerdd305c32010-05-11 14:05:32 +0200721 len = p - db + 2;
722 source = msi_alloc( len * sizeof(WCHAR) );
723 lstrcpynW( source, db, len );
724 msi_free( db );
725 }
James Hawkinsc777d302008-01-05 13:45:13 -0700726
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200727 check = msi_dup_property( package->db, cszSourceDir );
James Hawkinsc777d302008-01-05 13:45:13 -0700728 if (!check || replace)
Hans Leidekker44b79832010-04-21 11:38:17 +0200729 {
Hans Leidekkere31ee692010-04-21 11:38:40 +0200730 UINT r = msi_set_property( package->db, cszSourceDir, source );
Hans Leidekker44b79832010-04-21 11:38:17 +0200731 if (r == ERROR_SUCCESS)
732 msi_reset_folders( package, TRUE );
733 }
James Hawkinsc777d302008-01-05 13:45:13 -0700734 msi_free( check );
735
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200736 check = msi_dup_property( package->db, cszSOURCEDIR );
James Hawkinsc777d302008-01-05 13:45:13 -0700737 if (!check || replace)
Hans Leidekkere31ee692010-04-21 11:38:40 +0200738 msi_set_property( package->db, cszSOURCEDIR, source );
James Hawkinsc777d302008-01-05 13:45:13 -0700739
740 msi_free( check );
741 msi_free( source );
742
743 return ERROR_SUCCESS;
744}
745
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200746static BOOL needs_ui_sequence(MSIPACKAGE *package)
747{
Hans Leidekker186f4ef2010-04-21 11:37:54 +0200748 INT level = msi_get_property_int(package->db, szUILevel, 0);
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200749 return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
750}
751
Hans Leidekker82d7b042010-05-05 14:37:55 +0200752UINT msi_set_context(MSIPACKAGE *package)
James Hawkins5f112622008-06-18 00:50:28 -0500753{
Hans Leidekkerdf6b1952010-04-29 09:39:08 +0200754 int num;
James Hawkins5f112622008-06-18 00:50:28 -0500755
James Hawkins5f112622008-06-18 00:50:28 -0500756 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
757
Hans Leidekkerdf6b1952010-04-29 09:39:08 +0200758 num = msi_get_property_int(package->db, szAllUsers, 0);
759 if (num == 1 || num == 2)
760 package->Context = MSIINSTALLCONTEXT_MACHINE;
James Hawkins5f112622008-06-18 00:50:28 -0500761
James Hawkins5f112622008-06-18 00:50:28 -0500762 return ERROR_SUCCESS;
763}
764
Aric Stewart2703d712005-06-20 15:33:10 +0000765static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
766{
Aric Stewart2703d712005-06-20 15:33:10 +0000767 UINT rc;
768 LPCWSTR cond, action;
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200769 MSIPACKAGE *package = param;
Aric Stewart2703d712005-06-20 15:33:10 +0000770
771 action = MSI_RecordGetString(row,1);
772 if (!action)
773 {
774 ERR("Error is retrieving action name\n");
Mike McCormack9375fd92006-10-27 17:29:02 +0900775 return ERROR_FUNCTION_FAILED;
Aric Stewart2703d712005-06-20 15:33:10 +0000776 }
777
778 /* check conditions */
779 cond = MSI_RecordGetString(row,2);
Mike McCormack9375fd92006-10-27 17:29:02 +0900780
781 /* this is a hack to skip errors in the condition code */
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200782 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
Aric Stewart2703d712005-06-20 15:33:10 +0000783 {
Mike McCormack9375fd92006-10-27 17:29:02 +0900784 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
785 return ERROR_SUCCESS;
Aric Stewart2703d712005-06-20 15:33:10 +0000786 }
787
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200788 if (needs_ui_sequence(package))
789 rc = ACTION_PerformUIAction(package, action, -1);
Aric Stewart2703d712005-06-20 15:33:10 +0000790 else
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200791 rc = ACTION_PerformAction(package, action, -1, FALSE);
Aric Stewart2703d712005-06-20 15:33:10 +0000792
Mike McCormack4f634a32005-07-06 15:44:51 +0000793 msi_dialog_check_messages( NULL );
794
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200795 if (package->CurrentInstallState != ERROR_SUCCESS)
796 rc = package->CurrentInstallState;
Mike McCormack4f634a32005-07-06 15:44:51 +0000797
Aric Stewart2703d712005-06-20 15:33:10 +0000798 if (rc == ERROR_FUNCTION_NOT_CALLED)
799 rc = ERROR_SUCCESS;
800
801 if (rc != ERROR_SUCCESS)
Mike McCormack558abec2005-10-27 12:39:28 +0000802 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
Aric Stewart2703d712005-06-20 15:33:10 +0000803
804 return rc;
805}
806
Mike McCormackd34b1c22005-09-21 10:55:23 +0000807UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
808{
809 MSIQUERY * view;
810 UINT r;
811 static const WCHAR query[] =
812 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
813 '`','%','s','`',
814 ' ','W','H','E','R','E',' ',
815 '`','S','e','q','u','e','n','c','e','`',' ',
816 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
817 '`','S','e','q','u','e','n','c','e','`',0};
Mike McCormackd34b1c22005-09-21 10:55:23 +0000818
819 TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
820
821 r = MSI_OpenQuery( package->db, &view, query, szTable );
822 if (r == ERROR_SUCCESS)
823 {
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200824 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
Mike McCormackd34b1c22005-09-21 10:55:23 +0000825 msiobj_release(&view->hdr);
826 }
827
828 return r;
829}
830
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000831static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000832{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000833 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000834 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000835 static const WCHAR ExecSeqQuery[] =
836 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000837 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
838 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
839 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000840 'O','R','D','E','R',' ', 'B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000841 '`','S','e','q','u','e','n','c','e','`',0 };
Aric Stewart8e233e92005-03-01 11:45:19 +0000842 static const WCHAR IVQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +0000843 {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
844 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
845 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
846 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
847 ' ','\'', 'I','n','s','t','a','l','l',
848 'V','a','l','i','d','a','t','e','\'', 0};
Mike McCormack9db0e072004-12-22 15:05:07 +0000849 INT seq = 0;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000850
Aric Stewart9cd707d2005-05-27 19:24:22 +0000851 if (package->script->ExecuteSequenceRun)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +0000852 {
853 TRACE("Execute Sequence already Run\n");
854 return ERROR_SUCCESS;
855 }
856
Aric Stewart9cd707d2005-05-27 19:24:22 +0000857 package->script->ExecuteSequenceRun = TRUE;
Aric Stewart2703d712005-06-20 15:33:10 +0000858
Mike McCormack9db0e072004-12-22 15:05:07 +0000859 /* get the sequence number */
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000860 if (UIran)
861 {
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200862 MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
Mike McCormack0b352c72005-06-02 10:29:57 +0000863 if( !row )
864 return ERROR_FUNCTION_FAILED;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000865 seq = MSI_RecordGetInteger(row,1);
866 msiobj_release(&row->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000867 }
Mike McCormack9db0e072004-12-22 15:05:07 +0000868
Mike McCormack0c238852005-01-21 16:19:11 +0000869 rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000870 if (rc == ERROR_SUCCESS)
871 {
Aric Stewart2703d712005-06-20 15:33:10 +0000872 TRACE("Running the actions\n");
Aric Stewart401bd3f2004-06-28 20:34:35 +0000873
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200874 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000875 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +0000876 }
877
Aric Stewart401bd3f2004-06-28 20:34:35 +0000878 return rc;
879}
880
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000881static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000882{
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000883 MSIQUERY * view;
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000884 UINT rc;
Aric Stewart8e233e92005-03-01 11:45:19 +0000885 static const WCHAR ExecSeqQuery [] =
886 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000887 '`','I','n','s','t','a','l','l',
888 'U','I','S','e','q','u','e','n','c','e','`',
889 ' ','W','H','E','R','E',' ',
890 '`','S','e','q','u','e','n','c','e','`',' ',
Aric Stewart8e233e92005-03-01 11:45:19 +0000891 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
Aric Stewart98e38082005-05-20 09:40:42 +0000892 '`','S','e','q','u','e','n','c','e','`',0};
Aric Stewart2703d712005-06-20 15:33:10 +0000893
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000894 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000895 if (rc == ERROR_SUCCESS)
896 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000897 TRACE("Running the actions\n");
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000898
Hans Leidekkere3aa2f32009-10-15 12:48:26 +0200899 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +0000900 msiobj_release(&view->hdr);
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000901 }
902
Aric Stewarted7c4bc2004-07-04 00:26:54 +0000903 return rc;
904}
905
Aric Stewart401bd3f2004-06-28 20:34:35 +0000906/********************************************************
907 * ACTION helper functions and functions that perform the actions
908 *******************************************************/
Mike McCormackf9acfe62005-06-07 20:29:51 +0000909static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100910 UINT* rc, UINT script, BOOL force )
Aric Stewart3f318602005-02-01 18:46:26 +0000911{
912 BOOL ret=FALSE;
913 UINT arc;
914
Rob Shearman8a94f7a2007-06-25 20:47:38 +0100915 arc = ACTION_CustomAction(package, action, script, force);
Aric Stewart3f318602005-02-01 18:46:26 +0000916
917 if (arc != ERROR_CALL_NOT_IMPLEMENTED)
918 {
919 *rc = arc;
920 ret = TRUE;
921 }
922 return ret;
923}
Aric Stewart401bd3f2004-06-28 20:34:35 +0000924
Aric Stewart2274ff12005-06-21 20:03:46 +0000925/*
926 * Actual Action Handlers
927 */
928
929static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
930{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +0100931 MSIPACKAGE *package = param;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +0100932 LPCWSTR dir, component;
Aric Stewart2274ff12005-06-21 20:03:46 +0000933 LPWSTR full_path;
934 MSIRECORD *uirow;
935 MSIFOLDER *folder;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +0100936 MSICOMPONENT *comp;
937
938 component = MSI_RecordGetString(row, 2);
939 comp = get_loaded_component(package, component);
940 if (!comp)
941 return ERROR_SUCCESS;
942
943 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
944 {
945 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
946 comp->Action = comp->Installed;
947 return ERROR_SUCCESS;
948 }
949 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart2274ff12005-06-21 20:03:46 +0000950
951 dir = MSI_RecordGetString(row,1);
952 if (!dir)
953 {
Francois Gouget0edbaf72005-11-10 12:14:56 +0000954 ERR("Unable to get folder id\n");
Aric Stewart2274ff12005-06-21 20:03:46 +0000955 return ERROR_SUCCESS;
956 }
957
Hans Leidekkera70d86d2010-03-05 12:24:18 +0100958 uirow = MSI_CreateRecord(1);
959 MSI_RecordSetStringW(uirow, 1, dir);
960 ui_actiondata(package, szCreateFolders, uirow);
961 msiobj_release(&uirow->hdr);
962
James Hawkins8cedb212007-03-29 02:38:57 -0500963 full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
Aric Stewart2274ff12005-06-21 20:03:46 +0000964 if (!full_path)
965 {
966 ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
967 return ERROR_SUCCESS;
968 }
969
970 TRACE("Folder is %s\n",debugstr_w(full_path));
971
Aric Stewart2274ff12005-06-21 20:03:46 +0000972 if (folder->State == 0)
973 create_full_pathW(full_path);
974
975 folder->State = 3;
976
Mike McCormackee034ba2005-09-20 11:59:14 +0000977 msi_free(full_path);
Aric Stewart2274ff12005-06-21 20:03:46 +0000978 return ERROR_SUCCESS;
979}
980
Mike McCormack03b4dbb2005-10-28 09:39:29 +0000981/* FIXME: probably should merge this with the above function */
982static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
983{
984 UINT rc = ERROR_SUCCESS;
985 MSIFOLDER *folder;
986 LPWSTR install_path;
987
James Hawkins8cedb212007-03-29 02:38:57 -0500988 install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
Mike McCormack03b4dbb2005-10-28 09:39:29 +0000989 if (!install_path)
990 return ERROR_FUNCTION_FAILED;
991
992 /* create the path */
993 if (folder->State == 0)
994 {
995 create_full_pathW(install_path);
996 folder->State = 2;
997 }
998 msi_free(install_path);
999
1000 return rc;
1001}
Aric Stewart2274ff12005-06-21 20:03:46 +00001002
Mike McCormack9c845852005-10-29 11:29:17 +00001003UINT msi_create_component_directories( MSIPACKAGE *package )
1004{
1005 MSICOMPONENT *comp;
1006
1007 /* create all the folders required by the components are going to install */
1008 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1009 {
Hans Leidekker598c5422010-02-16 11:44:47 +01001010 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Mike McCormack9c845852005-10-29 11:29:17 +00001011 continue;
1012 msi_create_directory( package, comp->Directory );
1013 }
1014
1015 return ERROR_SUCCESS;
1016}
1017
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001018static UINT ACTION_CreateFolders(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00001019{
Aric Stewart8e233e92005-03-01 11:45:19 +00001020 static const WCHAR ExecSeqQuery[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001021 {'S','E','L','E','C','T',' ',
1022 '`','D','i','r','e','c','t','o','r','y','_','`',
Aric Stewart8e233e92005-03-01 11:45:19 +00001023 ' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001024 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00001025 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001026 MSIQUERY *view;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001027
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001028 /* create all the empty folders specified in the CreateFolder table */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001029 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
Aric Stewart401bd3f2004-06-28 20:34:35 +00001030 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00001031 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00001032
Aric Stewart2274ff12005-06-21 20:03:46 +00001033 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001034 msiobj_release(&view->hdr);
Mike McCormack03b4dbb2005-10-28 09:39:29 +00001035
Aric Stewart401bd3f2004-06-28 20:34:35 +00001036 return rc;
1037}
1038
Hans Leidekker3864ddf2010-02-05 14:47:55 +01001039static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
1040{
1041 MSIPACKAGE *package = param;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +01001042 LPCWSTR dir, component;
Hans Leidekker3864ddf2010-02-05 14:47:55 +01001043 LPWSTR full_path;
1044 MSIRECORD *uirow;
1045 MSIFOLDER *folder;
Hans Leidekker9cbb80d2010-02-16 11:45:34 +01001046 MSICOMPONENT *comp;
1047
1048 component = MSI_RecordGetString(row, 2);
1049 comp = get_loaded_component(package, component);
1050 if (!comp)
1051 return ERROR_SUCCESS;
1052
1053 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
1054 {
1055 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
1056 comp->Action = comp->Installed;
1057 return ERROR_SUCCESS;
1058 }
1059 comp->Action = INSTALLSTATE_ABSENT;
Hans Leidekker3864ddf2010-02-05 14:47:55 +01001060
1061 dir = MSI_RecordGetString( row, 1 );
1062 if (!dir)
1063 {
1064 ERR("Unable to get folder id\n");
1065 return ERROR_SUCCESS;
1066 }
1067
1068 full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder );
1069 if (!full_path)
1070 {
1071 ERR("Unable to resolve folder id %s\n", debugstr_w(dir));
1072 return ERROR_SUCCESS;
1073 }
1074
1075 TRACE("folder is %s\n", debugstr_w(full_path));
1076
1077 uirow = MSI_CreateRecord( 1 );
1078 MSI_RecordSetStringW( uirow, 1, full_path );
1079 ui_actiondata( package, szRemoveFolders, uirow );
1080 msiobj_release( &uirow->hdr );
1081
1082 RemoveDirectoryW( full_path );
1083 folder->State = 0;
1084
1085 msi_free( full_path );
1086 return ERROR_SUCCESS;
1087}
1088
1089static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
1090{
1091 static const WCHAR query[] =
1092 {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`',
1093 ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
1094
1095 MSIQUERY *view;
1096 UINT rc;
1097
1098 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
1099 if (rc != ERROR_SUCCESS)
1100 return ERROR_SUCCESS;
1101
1102 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
1103 msiobj_release( &view->hdr );
1104
1105 return rc;
1106}
1107
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001108static UINT load_component( MSIRECORD *row, LPVOID param )
Aric Stewartbdb29552004-07-04 00:32:48 +00001109{
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001110 MSIPACKAGE *package = param;
Mike McCormack38d67a42005-08-22 09:15:23 +00001111 MSICOMPONENT *comp;
Aric Stewartbdb29552004-07-04 00:32:48 +00001112
Mike McCormackee034ba2005-09-20 11:59:14 +00001113 comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
Mike McCormack38d67a42005-08-22 09:15:23 +00001114 if (!comp)
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001115 return ERROR_FUNCTION_FAILED;
1116
1117 list_add_tail( &package->components, &comp->entry );
Mike McCormack38d67a42005-08-22 09:15:23 +00001118
Aric Stewartbdb29552004-07-04 00:32:48 +00001119 /* fill in the data */
Mike McCormack51c66182005-10-27 12:36:12 +00001120 comp->Component = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001121
Mike McCormackefcc1ec2005-09-12 12:07:15 +00001122 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
Aric Stewartbdb29552004-07-04 00:32:48 +00001123
Mike McCormack51c66182005-10-27 12:36:12 +00001124 comp->ComponentId = msi_dup_record_field( row, 2 );
1125 comp->Directory = msi_dup_record_field( row, 3 );
Mike McCormack38d67a42005-08-22 09:15:23 +00001126 comp->Attributes = MSI_RecordGetInteger(row,4);
Mike McCormack51c66182005-10-27 12:36:12 +00001127 comp->Condition = msi_dup_record_field( row, 5 );
1128 comp->KeyPath = msi_dup_record_field( row, 6 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001129
James Hawkinsd893cb72006-09-20 19:55:01 -07001130 comp->Installed = INSTALLSTATE_UNKNOWN;
James Hawkins3bec1622008-08-25 00:07:52 -05001131 msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001132
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001133 return ERROR_SUCCESS;
1134}
Aric Stewartbdb29552004-07-04 00:32:48 +00001135
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001136static UINT load_all_components( MSIPACKAGE *package )
1137{
1138 static const WCHAR query[] = {
1139 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1140 '`','C','o','m','p','o','n','e','n','t','`',0 };
1141 MSIQUERY *view;
1142 UINT r;
1143
1144 if (!list_empty(&package->components))
1145 return ERROR_SUCCESS;
1146
1147 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1148 if (r != ERROR_SUCCESS)
1149 return r;
1150
1151 r = MSI_IterateRecords(view, NULL, load_component, package);
1152 msiobj_release(&view->hdr);
1153 return r;
Aric Stewartbdb29552004-07-04 00:32:48 +00001154}
1155
Aric Stewart04598242005-06-23 16:43:24 +00001156typedef struct {
1157 MSIPACKAGE *package;
Mike McCormack1da28582005-08-22 14:09:17 +00001158 MSIFEATURE *feature;
Aric Stewart04598242005-06-23 16:43:24 +00001159} _ilfs;
1160
Mike McCormack38d67a42005-08-22 09:15:23 +00001161static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001162{
1163 ComponentList *cl;
1164
Mike McCormackee034ba2005-09-20 11:59:14 +00001165 cl = msi_alloc( sizeof (*cl) );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001166 if ( !cl )
1167 return ERROR_NOT_ENOUGH_MEMORY;
Mike McCormack38d67a42005-08-22 09:15:23 +00001168 cl->component = comp;
Mike McCormack1da28582005-08-22 14:09:17 +00001169 list_add_tail( &feature->Components, &cl->entry );
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001170
1171 return ERROR_SUCCESS;
1172}
1173
James Hawkins545d0e72006-09-20 19:59:19 -07001174static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1175{
1176 FeatureList *fl;
1177
1178 fl = msi_alloc( sizeof(*fl) );
1179 if ( !fl )
1180 return ERROR_NOT_ENOUGH_MEMORY;
1181 fl->feature = child;
1182 list_add_tail( &parent->Children, &fl->entry );
1183
1184 return ERROR_SUCCESS;
1185}
1186
Aric Stewart04598242005-06-23 16:43:24 +00001187static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1188{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001189 _ilfs* ilfs = param;
Aric Stewart04598242005-06-23 16:43:24 +00001190 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00001191 MSICOMPONENT *comp;
Aric Stewart04598242005-06-23 16:43:24 +00001192
1193 component = MSI_RecordGetString(row,1);
1194
1195 /* check to see if the component is already loaded */
Mike McCormack38d67a42005-08-22 09:15:23 +00001196 comp = get_loaded_component( ilfs->package, component );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001197 if (!comp)
Aric Stewart04598242005-06-23 16:43:24 +00001198 {
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001199 ERR("unknown component %s\n", debugstr_w(component));
1200 return ERROR_FUNCTION_FAILED;
Aric Stewart04598242005-06-23 16:43:24 +00001201 }
1202
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001203 add_feature_component( ilfs->feature, comp );
1204 comp->Enabled = TRUE;
Aric Stewart04598242005-06-23 16:43:24 +00001205
1206 return ERROR_SUCCESS;
1207}
1208
James Hawkins545d0e72006-09-20 19:59:19 -07001209static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1210{
1211 MSIFEATURE *feature;
1212
James Hawkinsbfe07d12008-04-30 04:22:46 -05001213 if ( !name )
1214 return NULL;
1215
James Hawkins545d0e72006-09-20 19:59:19 -07001216 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1217 {
1218 if ( !lstrcmpW( feature->Feature, name ) )
1219 return feature;
1220 }
1221
1222 return NULL;
1223}
1224
Aric Stewart04598242005-06-23 16:43:24 +00001225static UINT load_feature(MSIRECORD * row, LPVOID param)
1226{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001227 MSIPACKAGE* package = param;
Mike McCormack1da28582005-08-22 14:09:17 +00001228 MSIFEATURE* feature;
Aric Stewart8e233e92005-03-01 11:45:19 +00001229 static const WCHAR Query1[] =
Aric Stewart98e38082005-05-20 09:40:42 +00001230 {'S','E','L','E','C','T',' ',
1231 '`','C','o','m','p','o','n','e','n','t','_','`',
1232 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1233 'C','o','m','p','o','n','e','n','t','s','`',' ',
1234 'W','H','E','R','E',' ',
1235 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001236 MSIQUERY * view;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001237 UINT rc;
Aric Stewart04598242005-06-23 16:43:24 +00001238 _ilfs ilfs;
1239
Aric Stewartbdb29552004-07-04 00:32:48 +00001240 /* fill in the data */
1241
Mike McCormackee034ba2005-09-20 11:59:14 +00001242 feature = msi_alloc_zero( sizeof (MSIFEATURE) );
Mike McCormack1da28582005-08-22 14:09:17 +00001243 if (!feature)
1244 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartbdb29552004-07-04 00:32:48 +00001245
James Hawkins545d0e72006-09-20 19:59:19 -07001246 list_init( &feature->Children );
Mike McCormack1da28582005-08-22 14:09:17 +00001247 list_init( &feature->Components );
Aric Stewartbdb29552004-07-04 00:32:48 +00001248
Mike McCormack51c66182005-10-27 12:36:12 +00001249 feature->Feature = msi_dup_record_field( row, 1 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001250
Mike McCormack1da28582005-08-22 14:09:17 +00001251 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
Aric Stewartbdb29552004-07-04 00:32:48 +00001252
Mike McCormack51c66182005-10-27 12:36:12 +00001253 feature->Feature_Parent = msi_dup_record_field( row, 2 );
1254 feature->Title = msi_dup_record_field( row, 3 );
1255 feature->Description = msi_dup_record_field( row, 4 );
Aric Stewartbdb29552004-07-04 00:32:48 +00001256
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001257 if (!MSI_RecordIsNull(row,5))
Mike McCormack1da28582005-08-22 14:09:17 +00001258 feature->Display = MSI_RecordGetInteger(row,5);
Aric Stewartbdb29552004-07-04 00:32:48 +00001259
Mike McCormack1da28582005-08-22 14:09:17 +00001260 feature->Level= MSI_RecordGetInteger(row,6);
Mike McCormack51c66182005-10-27 12:36:12 +00001261 feature->Directory = msi_dup_record_field( row, 7 );
Mike McCormack1da28582005-08-22 14:09:17 +00001262 feature->Attributes = MSI_RecordGetInteger(row,8);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001263
James Hawkinsca5c1102006-09-20 19:53:56 -07001264 feature->Installed = INSTALLSTATE_UNKNOWN;
James Hawkinsd596ae22008-08-25 00:07:18 -05001265 msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
Mike McCormack1da28582005-08-22 14:09:17 +00001266
1267 list_add_tail( &package->features, &feature->entry );
Aric Stewartbdb29552004-07-04 00:32:48 +00001268
1269 /* load feature components */
1270
Mike McCormack1da28582005-08-22 14:09:17 +00001271 rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001272 if (rc != ERROR_SUCCESS)
Aric Stewart04598242005-06-23 16:43:24 +00001273 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001274
Mike McCormack1da28582005-08-22 14:09:17 +00001275 ilfs.package = package;
1276 ilfs.feature = feature;
1277
Aric Stewart04598242005-06-23 16:43:24 +00001278 MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001279 msiobj_release(&view->hdr);
Aric Stewart04598242005-06-23 16:43:24 +00001280
1281 return ERROR_SUCCESS;
Aric Stewartbdb29552004-07-04 00:32:48 +00001282}
1283
James Hawkins545d0e72006-09-20 19:59:19 -07001284static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1285{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001286 MSIPACKAGE* package = param;
James Hawkins545d0e72006-09-20 19:59:19 -07001287 MSIFEATURE *parent, *child;
1288
1289 child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1290 if (!child)
1291 return ERROR_FUNCTION_FAILED;
1292
1293 if (!child->Feature_Parent)
1294 return ERROR_SUCCESS;
1295
1296 parent = find_feature_by_name( package, child->Feature_Parent );
1297 if (!parent)
1298 return ERROR_FUNCTION_FAILED;
1299
1300 add_feature_child( parent, child );
1301 return ERROR_SUCCESS;
1302}
1303
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001304static UINT load_all_features( MSIPACKAGE *package )
1305{
1306 static const WCHAR query[] = {
1307 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1308 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1309 ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1310 MSIQUERY *view;
1311 UINT r;
1312
1313 if (!list_empty(&package->features))
1314 return ERROR_SUCCESS;
1315
1316 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1317 if (r != ERROR_SUCCESS)
1318 return r;
1319
1320 r = MSI_IterateRecords( view, NULL, load_feature, package );
James Hawkins545d0e72006-09-20 19:59:19 -07001321 if (r != ERROR_SUCCESS)
1322 return r;
1323
1324 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001325 msiobj_release( &view->hdr );
James Hawkins545d0e72006-09-20 19:59:19 -07001326
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001327 return r;
1328}
1329
Mike McCormackc1513be2006-03-21 19:40:36 +09001330static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1331{
1332 if (!p)
1333 return p;
1334 p = strchrW(p, ch);
1335 if (!p)
1336 return p;
1337 *p = 0;
1338 return p+1;
1339}
1340
James Hawkins41607222007-11-25 18:01:19 -06001341static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1342{
1343 static const WCHAR query[] = {
1344 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1345 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1346 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1347 MSIQUERY *view = NULL;
James Hawkins1277e1b2007-12-14 15:18:05 -06001348 MSIRECORD *row = NULL;
James Hawkins41607222007-11-25 18:01:19 -06001349 UINT r;
1350
1351 TRACE("%s\n", debugstr_w(file->File));
1352
1353 r = MSI_OpenQuery(package->db, &view, query, file->File);
1354 if (r != ERROR_SUCCESS)
1355 goto done;
1356
1357 r = MSI_ViewExecute(view, NULL);
1358 if (r != ERROR_SUCCESS)
1359 goto done;
1360
1361 r = MSI_ViewFetch(view, &row);
1362 if (r != ERROR_SUCCESS)
1363 goto done;
1364
1365 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1366 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1367 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1368 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1369 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1370
1371done:
1372 if (view) msiobj_release(&view->hdr);
James Hawkins1277e1b2007-12-14 15:18:05 -06001373 if (row) msiobj_release(&row->hdr);
James Hawkins41607222007-11-25 18:01:19 -06001374 return r;
1375}
1376
Hans Leidekker376c2fd2010-05-12 14:18:15 +02001377static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1378{
1379 MSIRECORD *row;
1380 static const WCHAR query[] = {
1381 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
1382 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
1383 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
1384
1385 row = MSI_QueryGetRecord( package->db, query, file->Sequence );
1386 if (!row)
1387 {
1388 WARN("query failed\n");
1389 return ERROR_FUNCTION_FAILED;
1390 }
1391
1392 file->disk_id = MSI_RecordGetInteger( row, 1 );
1393 msiobj_release( &row->hdr );
1394 return ERROR_SUCCESS;
1395}
1396
Aric Stewart04598242005-06-23 16:43:24 +00001397static UINT load_file(MSIRECORD *row, LPVOID param)
Aric Stewartc5a14432005-05-18 17:46:12 +00001398{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001399 MSIPACKAGE* package = param;
Aric Stewart09b0aba2005-06-09 20:30:59 +00001400 LPCWSTR component;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001401 MSIFILE *file;
Aric Stewartc5a14432005-05-18 17:46:12 +00001402
1403 /* fill in the data */
1404
Mike McCormackee034ba2005-09-20 11:59:14 +00001405 file = msi_alloc_zero( sizeof (MSIFILE) );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001406 if (!file)
1407 return ERROR_NOT_ENOUGH_MEMORY;
Aric Stewartc5a14432005-05-18 17:46:12 +00001408
Mike McCormack51c66182005-10-27 12:36:12 +00001409 file->File = msi_dup_record_field( row, 1 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001410
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001411 component = MSI_RecordGetString( row, 2 );
1412 file->Component = get_loaded_component( package, component );
Aric Stewart09b0aba2005-06-09 20:30:59 +00001413
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001414 if (!file->Component)
James Hawkins9a8d2f32008-08-18 23:00:20 -05001415 {
1416 WARN("Component not found: %s\n", debugstr_w(component));
1417 msi_free(file->File);
1418 msi_free(file);
1419 return ERROR_SUCCESS;
1420 }
Aric Stewartc5a14432005-05-18 17:46:12 +00001421
Mike McCormack51c66182005-10-27 12:36:12 +00001422 file->FileName = msi_dup_record_field( row, 3 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001423 reduce_to_longfilename( file->FileName );
Aric Stewartc5a14432005-05-18 17:46:12 +00001424
Mike McCormack51c66182005-10-27 12:36:12 +00001425 file->ShortName = msi_dup_record_field( row, 3 );
Mike McCormackc1513be2006-03-21 19:40:36 +09001426 file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
Aric Stewartc5a14432005-05-18 17:46:12 +00001427
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001428 file->FileSize = MSI_RecordGetInteger( row, 4 );
Mike McCormack51c66182005-10-27 12:36:12 +00001429 file->Version = msi_dup_record_field( row, 5 );
1430 file->Language = msi_dup_record_field( row, 6 );
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001431 file->Attributes = MSI_RecordGetInteger( row, 7 );
1432 file->Sequence = MSI_RecordGetInteger( row, 8 );
Aric Stewartc5a14432005-05-18 17:46:12 +00001433
Mike McCormackdded8fb2005-11-02 10:56:42 +00001434 file->state = msifs_invalid;
Aric Stewartc5a14432005-05-18 17:46:12 +00001435
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001436 /* if the compressed bits are not set in the file attributes,
1437 * then read the information from the package word count property
1438 */
James Hawkinsf80b5f62008-10-16 22:55:21 -05001439 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1440 {
1441 file->IsCompressed = FALSE;
1442 }
1443 else if (file->Attributes &
1444 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
James Hawkins98d14862006-07-31 11:15:52 -07001445 {
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001446 file->IsCompressed = TRUE;
1447 }
1448 else if (file->Attributes & msidbFileAttributesNoncompressed)
1449 {
1450 file->IsCompressed = FALSE;
1451 }
1452 else
1453 {
James Hawkins7538f9a2008-07-22 00:54:27 -05001454 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
James Hawkinsf84fa0c2006-08-07 11:37:49 -07001455 }
1456
James Hawkins41607222007-11-25 18:01:19 -06001457 load_file_hash(package, file);
Hans Leidekker376c2fd2010-05-12 14:18:15 +02001458 load_file_disk_id(package, file);
James Hawkins41607222007-11-25 18:01:19 -06001459
Mike McCormacke18f8ab2005-08-23 10:03:17 +00001460 TRACE("File Loaded (%s)\n",debugstr_w(file->File));
1461
1462 list_add_tail( &package->files, &file->entry );
Aric Stewartc5a14432005-05-18 17:46:12 +00001463
1464 return ERROR_SUCCESS;
1465}
1466
1467static UINT load_all_files(MSIPACKAGE *package)
1468{
1469 MSIQUERY * view;
Aric Stewartc5a14432005-05-18 17:46:12 +00001470 UINT rc;
1471 static const WCHAR Query[] =
1472 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00001473 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1474 '`','S','e','q','u','e','n','c','e','`', 0};
Aric Stewartc5a14432005-05-18 17:46:12 +00001475
Mike McCormack9a9195d2006-07-19 17:01:07 +09001476 if (!list_empty(&package->files))
1477 return ERROR_SUCCESS;
1478
Aric Stewartc5a14432005-05-18 17:46:12 +00001479 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1480 if (rc != ERROR_SUCCESS)
1481 return ERROR_SUCCESS;
Aric Stewartc5a14432005-05-18 17:46:12 +00001482
Aric Stewart04598242005-06-23 16:43:24 +00001483 rc = MSI_IterateRecords(view, NULL, load_file, package);
Aric Stewartc5a14432005-05-18 17:46:12 +00001484 msiobj_release(&view->hdr);
1485
1486 return ERROR_SUCCESS;
1487}
1488
Mike McCormack7eb27022006-11-22 15:13:12 +09001489static UINT load_folder( MSIRECORD *row, LPVOID param )
1490{
1491 MSIPACKAGE *package = param;
Mike McCormack7eb27022006-11-22 15:13:12 +09001492 static WCHAR szEmpty[] = { 0 };
1493 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1494 MSIFOLDER *folder;
1495
1496 folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1497 if (!folder)
1498 return ERROR_NOT_ENOUGH_MEMORY;
1499
1500 folder->Directory = msi_dup_record_field( row, 1 );
1501
1502 TRACE("%s\n", debugstr_w(folder->Directory));
1503
1504 p = msi_dup_record_field(row, 3);
1505
1506 /* split src and target dir */
1507 tgt_short = p;
1508 src_short = folder_split_path( p, ':' );
1509
1510 /* split the long and short paths */
1511 tgt_long = folder_split_path( tgt_short, '|' );
1512 src_long = folder_split_path( src_short, '|' );
1513
1514 /* check for no-op dirs */
1515 if (!lstrcmpW(szDot, tgt_short))
1516 tgt_short = szEmpty;
1517 if (!lstrcmpW(szDot, src_short))
1518 src_short = szEmpty;
1519
1520 if (!tgt_long)
1521 tgt_long = tgt_short;
1522
1523 if (!src_short) {
1524 src_short = tgt_short;
1525 src_long = tgt_long;
1526 }
1527
1528 if (!src_long)
1529 src_long = src_short;
1530
1531 /* FIXME: use the target short path too */
1532 folder->TargetDefault = strdupW(tgt_long);
1533 folder->SourceShortPath = strdupW(src_short);
1534 folder->SourceLongPath = strdupW(src_long);
1535 msi_free(p);
1536
1537 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1538 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1539 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1540
1541 folder->Parent = msi_dup_record_field( row, 2 );
1542
Hans Leidekker186f4ef2010-04-21 11:37:54 +02001543 folder->Property = msi_dup_property( package->db, folder->Directory );
Mike McCormack7eb27022006-11-22 15:13:12 +09001544
1545 list_add_tail( &package->folders, &folder->entry );
1546
1547 TRACE("returning %p\n", folder);
1548
1549 return ERROR_SUCCESS;
1550}
1551
1552static UINT load_all_folders( MSIPACKAGE *package )
1553{
1554 static const WCHAR query[] = {
1555 'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1556 '`','D','i','r','e','c','t','o','r','y','`',0 };
1557 MSIQUERY *view;
1558 UINT r;
1559
1560 if (!list_empty(&package->folders))
1561 return ERROR_SUCCESS;
1562
1563 r = MSI_DatabaseOpenViewW( package->db, query, &view );
1564 if (r != ERROR_SUCCESS)
1565 return r;
1566
1567 r = MSI_IterateRecords(view, NULL, load_folder, package);
1568 msiobj_release(&view->hdr);
1569 return r;
1570}
Aric Stewartc5a14432005-05-18 17:46:12 +00001571
Aric Stewartbdb29552004-07-04 00:32:48 +00001572/*
Mike McCormack9a9195d2006-07-19 17:01:07 +09001573 * I am not doing any of the costing functionality yet.
Aric Stewartbdb29552004-07-04 00:32:48 +00001574 * Mostly looking at doing the Component and Feature loading
1575 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001576 * The native MSI does A LOT of modification to tables here. Mostly adding
Mike McCormack9a9195d2006-07-19 17:01:07 +09001577 * a lot of temporary columns to the Feature and Component tables.
Aric Stewartbdb29552004-07-04 00:32:48 +00001578 *
Francois Gougetda8b3dd2005-01-26 21:09:04 +00001579 * note: Native msi also tracks the short filename. But I am only going to
Aric Stewartbdb29552004-07-04 00:32:48 +00001580 * track the long ones. Also looking at this directory table
1581 * it appears that the directory table does not get the parents
Mike McCormack9a9195d2006-07-19 17:01:07 +09001582 * resolved base on property only based on their entries in the
Aric Stewartbdb29552004-07-04 00:32:48 +00001583 * directory table.
1584 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001585static UINT ACTION_CostInitialize(MSIPACKAGE *package)
Aric Stewartbdb29552004-07-04 00:32:48 +00001586{
Aric Stewart8e233e92005-03-01 11:45:19 +00001587 static const WCHAR szCosting[] =
1588 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
Aric Stewartbdb29552004-07-04 00:32:48 +00001589
Hans Leidekkere31ee692010-04-21 11:38:40 +02001590 msi_set_property( package->db, szCosting, szZero );
1591 msi_set_property( package->db, cszRootDrive, c_colon );
Aric Stewartbdb29552004-07-04 00:32:48 +00001592
James Hawkinsdbbd5ca2008-06-10 17:33:29 -05001593 load_all_folders( package );
Mike McCormack1d46cdf2006-07-25 21:49:44 +09001594 load_all_components( package );
1595 load_all_features( package );
1596 load_all_files( package );
Aric Stewartec688fb2004-07-04 00:35:52 +00001597
Aric Stewartec688fb2004-07-04 00:35:52 +00001598 return ERROR_SUCCESS;
1599}
1600
Mike McCormackf9acfe62005-06-07 20:29:51 +00001601static UINT execute_script(MSIPACKAGE *package, UINT script )
Aric Stewart9cd707d2005-05-27 19:24:22 +00001602{
James Hawkinsbb54ed12007-11-05 04:36:49 -05001603 UINT i;
Aric Stewart9cd707d2005-05-27 19:24:22 +00001604 UINT rc = ERROR_SUCCESS;
1605
1606 TRACE("Executing Script %i\n",script);
1607
Mike McCormackaa81e4f2006-01-10 12:09:19 +01001608 if (!package->script)
1609 {
1610 ERR("no script!\n");
1611 return ERROR_FUNCTION_FAILED;
1612 }
1613
Aric Stewart9cd707d2005-05-27 19:24:22 +00001614 for (i = 0; i < package->script->ActionCount[script]; i++)
1615 {
1616 LPWSTR action;
1617 action = package->script->Actions[script][i];
1618 ui_actionstart(package, action);
1619 TRACE("Executing Action (%s)\n",debugstr_w(action));
Rob Shearman8a94f7a2007-06-25 20:47:38 +01001620 rc = ACTION_PerformAction(package, action, script, TRUE);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001621 if (rc != ERROR_SUCCESS)
1622 break;
1623 }
Mike McCormackf86cfd42006-11-02 18:12:43 +09001624 msi_free_action_script(package, script);
Aric Stewart9cd707d2005-05-27 19:24:22 +00001625 return rc;
1626}
1627
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00001628static UINT ACTION_FileCost(MSIPACKAGE *package)
Aric Stewartec688fb2004-07-04 00:35:52 +00001629{
Aric Stewartbdb29552004-07-04 00:32:48 +00001630 return ERROR_SUCCESS;
1631}
1632
Mike McCormackb7669152006-10-30 16:35:09 +09001633static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
Aric Stewart78a04e32005-02-22 15:47:00 +00001634{
Mike McCormack38d67a42005-08-22 09:15:23 +00001635 MSICOMPONENT *comp;
James Hawkins42115632008-08-18 23:14:19 -05001636 INSTALLSTATE state;
1637 UINT r;
Aric Stewart78a04e32005-02-22 15:47:00 +00001638
James Hawkins42115632008-08-18 23:14:19 -05001639 state = MsiQueryProductStateW(package->ProductCode);
1640
1641 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
Aric Stewart78a04e32005-02-22 15:47:00 +00001642 {
James Hawkins32f57022006-09-20 19:57:03 -07001643 if (!comp->ComponentId)
1644 continue;
1645
James Hawkins42115632008-08-18 23:14:19 -05001646 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1647 comp->Installed = INSTALLSTATE_ABSENT;
1648 else
1649 {
1650 r = MsiQueryComponentStateW(package->ProductCode, NULL,
1651 package->Context, comp->ComponentId,
1652 &comp->Installed);
1653 if (r != ERROR_SUCCESS)
1654 comp->Installed = INSTALLSTATE_ABSENT;
1655 }
Aric Stewart78a04e32005-02-22 15:47:00 +00001656 }
Mike McCormackb7669152006-10-30 16:35:09 +09001657}
1658
James Hawkins5a3c3b62008-08-18 23:14:53 -05001659static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
Mike McCormackb7669152006-10-30 16:35:09 +09001660{
Mike McCormackb7669152006-10-30 16:35:09 +09001661 MSIFEATURE *feature;
James Hawkins5a3c3b62008-08-18 23:14:53 -05001662 INSTALLSTATE state;
1663
1664 state = MsiQueryProductStateW(package->ProductCode);
Aric Stewart78a04e32005-02-22 15:47:00 +00001665
Mike McCormack1da28582005-08-22 14:09:17 +00001666 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart78a04e32005-02-22 15:47:00 +00001667 {
James Hawkins5a3c3b62008-08-18 23:14:53 -05001668 if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1669 feature->Installed = INSTALLSTATE_ABSENT;
1670 else
Aric Stewart78a04e32005-02-22 15:47:00 +00001671 {
James Hawkins5a3c3b62008-08-18 23:14:53 -05001672 feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1673 feature->Feature);
Aric Stewart78a04e32005-02-22 15:47:00 +00001674 }
1675 }
1676}
1677
James Hawkinsc855fbf2008-08-25 00:06:43 -05001678static BOOL process_state_property(MSIPACKAGE* package, int level,
1679 LPCWSTR property, INSTALLSTATE state)
Aric Stewartae1aa322004-12-27 19:02:59 +00001680{
Mike McCormack72faac02005-09-08 11:03:35 +00001681 LPWSTR override;
Mike McCormack1da28582005-08-22 14:09:17 +00001682 MSIFEATURE *feature;
Aric Stewartae1aa322004-12-27 19:02:59 +00001683
Hans Leidekker186f4ef2010-04-21 11:37:54 +02001684 override = msi_dup_property( package->db, property );
Mike McCormack72faac02005-09-08 11:03:35 +00001685 if (!override)
1686 return FALSE;
Mike McCormack575cc672006-10-26 14:09:29 +09001687
Mike McCormack72faac02005-09-08 11:03:35 +00001688 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001689 {
Hans Leidekker843382f2009-10-15 12:46:27 +02001690 if (lstrcmpW(property, szRemove) &&
James Hawkinsc855fbf2008-08-25 00:06:43 -05001691 (feature->Level <= 0 || feature->Level > level))
1692 continue;
1693
Hans Leidekker843382f2009-10-15 12:46:27 +02001694 if (!strcmpW(property, szReinstall)) state = feature->Installed;
Hans Leidekker40cfbaf2009-03-12 11:46:35 +01001695
Hans Leidekker843382f2009-10-15 12:46:27 +02001696 if (strcmpiW(override, szAll)==0)
James Hawkinsd596ae22008-08-25 00:07:18 -05001697 msi_feature_set_state(package, feature, state);
Mike McCormack72faac02005-09-08 11:03:35 +00001698 else
1699 {
1700 LPWSTR ptr = override;
1701 LPWSTR ptr2 = strchrW(override,',');
Aric Stewartd900b532004-12-27 19:12:35 +00001702
Mike McCormack72faac02005-09-08 11:03:35 +00001703 while (ptr)
1704 {
Hans Leidekker2bfce6c2010-01-18 13:10:15 +01001705 int len = ptr2 - ptr;
1706
1707 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
1708 || (!ptr2 && !strcmpW(ptr, feature->Feature)))
Aric Stewartd900b532004-12-27 19:12:35 +00001709 {
James Hawkinsd596ae22008-08-25 00:07:18 -05001710 msi_feature_set_state(package, feature, state);
Mike McCormack72faac02005-09-08 11:03:35 +00001711 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001712 }
Mike McCormack72faac02005-09-08 11:03:35 +00001713 if (ptr2)
1714 {
1715 ptr=ptr2+1;
1716 ptr2 = strchrW(ptr,',');
1717 }
1718 else
1719 break;
Aric Stewartd900b532004-12-27 19:12:35 +00001720 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001721 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001722 }
Mike McCormackee034ba2005-09-20 11:59:14 +00001723 msi_free(override);
Aric Stewart78a04e32005-02-22 15:47:00 +00001724
Mike McCormack72faac02005-09-08 11:03:35 +00001725 return TRUE;
Aric Stewart78a04e32005-02-22 15:47:00 +00001726}
1727
Hans Leidekker0d770c92010-01-27 11:18:02 +01001728static BOOL process_overrides( MSIPACKAGE *package, int level )
Aric Stewart78a04e32005-02-22 15:47:00 +00001729{
Aric Stewart8e233e92005-03-01 11:45:19 +00001730 static const WCHAR szAddLocal[] =
1731 {'A','D','D','L','O','C','A','L',0};
James Hawkinsc31fd432007-11-06 05:22:11 -06001732 static const WCHAR szAddSource[] =
1733 {'A','D','D','S','O','U','R','C','E',0};
Hans Leidekker4da865f2009-03-13 11:34:46 +01001734 static const WCHAR szAdvertise[] =
1735 {'A','D','V','E','R','T','I','S','E',0};
Hans Leidekker0d770c92010-01-27 11:18:02 +01001736 BOOL ret = FALSE;
1737
1738 /* all these activation/deactivation things happen in order and things
1739 * later on the list override things earlier on the list.
1740 *
1741 * 0 INSTALLLEVEL processing
1742 * 1 ADDLOCAL
1743 * 2 REMOVE
1744 * 3 ADDSOURCE
1745 * 4 ADDDEFAULT
1746 * 5 REINSTALL
1747 * 6 ADVERTISE
1748 * 7 COMPADDLOCAL
1749 * 8 COMPADDSOURCE
1750 * 9 FILEADDLOCAL
1751 * 10 FILEADDSOURCE
1752 * 11 FILEADDDEFAULT
1753 */
1754 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
1755 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
1756 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
1757 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
1758 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
1759
1760 if (ret)
Hans Leidekkere31ee692010-04-21 11:38:40 +02001761 msi_set_property( package->db, szPreselected, szOne );
Hans Leidekker0d770c92010-01-27 11:18:02 +01001762
1763 return ret;
1764}
1765
1766UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1767{
1768 int level;
1769 static const WCHAR szlevel[] =
1770 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
Mike McCormack38d67a42005-08-22 09:15:23 +00001771 MSICOMPONENT* component;
Mike McCormack1da28582005-08-22 14:09:17 +00001772 MSIFEATURE *feature;
1773
Aric Stewart78a04e32005-02-22 15:47:00 +00001774 TRACE("Checking Install Level\n");
1775
Hans Leidekker186f4ef2010-04-21 11:37:54 +02001776 level = msi_get_property_int(package->db, szlevel, 1);
Aric Stewart78a04e32005-02-22 15:47:00 +00001777
Hans Leidekker186f4ef2010-04-21 11:37:54 +02001778 if (!msi_get_property_int( package->db, szPreselected, 0 ))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001779 {
Mike McCormack1da28582005-08-22 14:09:17 +00001780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001781 {
Mike McCormack1da28582005-08-22 14:09:17 +00001782 BOOL feature_state = ((feature->Level > 0) &&
James Hawkinsc855fbf2008-08-25 00:06:43 -05001783 (feature->Level <= level));
Aric Stewartae1aa322004-12-27 19:02:59 +00001784
Mike McCormack1da28582005-08-22 14:09:17 +00001785 if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
Aric Stewartfbdd7092004-12-27 19:06:22 +00001786 {
Mike McCormack1da28582005-08-22 14:09:17 +00001787 if (feature->Attributes & msidbFeatureAttributesFavorSource)
James Hawkinsd596ae22008-08-25 00:07:18 -05001788 msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
Mike McCormack1da28582005-08-22 14:09:17 +00001789 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
James Hawkinsd596ae22008-08-25 00:07:18 -05001790 msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00001791 else
James Hawkinsd596ae22008-08-25 00:07:18 -05001792 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001793 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001794 }
James Hawkins545d0e72006-09-20 19:59:19 -07001795
1796 /* disable child features of unselected parent features */
1797 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1798 {
1799 FeatureList *fl;
1800
James Hawkinsc855fbf2008-08-25 00:06:43 -05001801 if (feature->Level > 0 && feature->Level <= level)
James Hawkins545d0e72006-09-20 19:59:19 -07001802 continue;
1803
1804 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
James Hawkinsd596ae22008-08-25 00:07:18 -05001805 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
James Hawkins545d0e72006-09-20 19:59:19 -07001806 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001807 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001808
Aric Stewartfbdd7092004-12-27 19:06:22 +00001809 /*
Mike McCormack6395ff62006-10-26 12:34:52 +09001810 * now we want to enable or disable components base on feature
1811 */
Aric Stewartfbdd7092004-12-27 19:06:22 +00001812
Mike McCormack1da28582005-08-22 14:09:17 +00001813 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001814 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00001815 ComponentList *cl;
1816
James Hawkins62219752008-05-19 02:27:50 -05001817 TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1818 debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1819
1820 if (!feature->Level)
1821 continue;
Mike McCormack97419ae2006-12-05 18:24:39 +09001822
1823 /* features with components that have compressed files are made local */
1824 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1825 {
1826 if (cl->component->Enabled &&
1827 cl->component->ForceLocalState &&
1828 feature->Action == INSTALLSTATE_SOURCE)
1829 {
James Hawkinsd596ae22008-08-25 00:07:18 -05001830 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
Mike McCormack97419ae2006-12-05 18:24:39 +09001831 break;
1832 }
1833 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001834
Mike McCormack1da28582005-08-22 14:09:17 +00001835 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartae1aa322004-12-27 19:02:59 +00001836 {
Mike McCormack38d67a42005-08-22 09:15:23 +00001837 component = cl->component;
Aric Stewartfbdd7092004-12-27 19:06:22 +00001838
Mike McCormack87fa8542006-11-10 15:38:51 +09001839 if (!component->Enabled)
1840 continue;
1841
Mike McCormack97419ae2006-12-05 18:24:39 +09001842 switch (feature->Action)
Mike McCormackad80ece2006-11-10 15:38:31 +09001843 {
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001844 case INSTALLSTATE_ABSENT:
1845 component->anyAbsent = 1;
1846 break;
Mike McCormack97419ae2006-12-05 18:24:39 +09001847 case INSTALLSTATE_ADVERTISED:
1848 component->hasAdvertiseFeature = 1;
1849 break;
1850 case INSTALLSTATE_SOURCE:
1851 component->hasSourceFeature = 1;
1852 break;
1853 case INSTALLSTATE_LOCAL:
1854 component->hasLocalFeature = 1;
1855 break;
1856 case INSTALLSTATE_DEFAULT:
1857 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1858 component->hasAdvertiseFeature = 1;
1859 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1860 component->hasSourceFeature = 1;
Mike McCormackad80ece2006-11-10 15:38:31 +09001861 else
Mike McCormack97419ae2006-12-05 18:24:39 +09001862 component->hasLocalFeature = 1;
1863 break;
1864 default:
1865 break;
James Hawkins929395c2006-10-19 15:51:33 -07001866 }
Aric Stewartae1aa322004-12-27 19:02:59 +00001867 }
Mike McCormack6395ff62006-10-26 12:34:52 +09001868 }
Aric Stewartfbdd7092004-12-27 19:06:22 +00001869
Mike McCormack38d67a42005-08-22 09:15:23 +00001870 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
Aric Stewartfbdd7092004-12-27 19:06:22 +00001871 {
Mike McCormack97419ae2006-12-05 18:24:39 +09001872 /* if the component isn't enabled, leave it alone */
1873 if (!component->Enabled)
1874 continue;
1875
1876 /* check if it's local or source */
1877 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1878 (component->hasLocalFeature || component->hasSourceFeature))
1879 {
1880 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1881 !component->ForceLocalState)
James Hawkins3bec1622008-08-25 00:07:52 -05001882 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
Mike McCormack97419ae2006-12-05 18:24:39 +09001883 else
James Hawkins3bec1622008-08-25 00:07:52 -05001884 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
Mike McCormack97419ae2006-12-05 18:24:39 +09001885 continue;
1886 }
1887
1888 /* if any feature is local, the component must be local too */
1889 if (component->hasLocalFeature)
1890 {
James Hawkins3bec1622008-08-25 00:07:52 -05001891 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
Mike McCormack97419ae2006-12-05 18:24:39 +09001892 continue;
1893 }
1894
1895 if (component->hasSourceFeature)
1896 {
James Hawkins3bec1622008-08-25 00:07:52 -05001897 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
Mike McCormack97419ae2006-12-05 18:24:39 +09001898 continue;
1899 }
1900
1901 if (component->hasAdvertiseFeature)
1902 {
James Hawkins3bec1622008-08-25 00:07:52 -05001903 msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
Mike McCormack97419ae2006-12-05 18:24:39 +09001904 continue;
1905 }
1906
1907 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05001908 if (component->anyAbsent)
James Hawkins3bec1622008-08-25 00:07:52 -05001909 msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
Mike McCormack97419ae2006-12-05 18:24:39 +09001910 }
1911
1912 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1913 {
Mike McCormack9efb7b72006-11-07 17:55:43 +09001914 if (component->Action == INSTALLSTATE_DEFAULT)
1915 {
1916 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
James Hawkins3bec1622008-08-25 00:07:52 -05001917 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
Mike McCormack9efb7b72006-11-07 17:55:43 +09001918 }
1919
Mike McCormack3fe6a5d2006-11-10 15:39:01 +09001920 TRACE("Result: Component %s (Installed %i, Action %i)\n",
1921 debugstr_w(component->Component), component->Installed, component->Action);
Aric Stewartfbdd7092004-12-27 19:06:22 +00001922 }
1923
1924
Aric Stewartae1aa322004-12-27 19:02:59 +00001925 return ERROR_SUCCESS;
1926}
1927
Aric Stewart443ad4d2005-06-21 20:50:12 +00001928static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1929{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001930 MSIPACKAGE *package = param;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001931 LPCWSTR name;
1932 LPWSTR path;
James Hawkinsbaad8882007-05-01 03:19:50 -05001933 MSIFOLDER *f;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001934
1935 name = MSI_RecordGetString(row,1);
1936
James Hawkinsbaad8882007-05-01 03:19:50 -05001937 f = get_loaded_folder(package, name);
1938 if (!f) return ERROR_SUCCESS;
1939
1940 /* reset the ResolvedTarget */
1941 msi_free(f->ResolvedTarget);
1942 f->ResolvedTarget = NULL;
1943
Aric Stewart443ad4d2005-06-21 20:50:12 +00001944 /* This helper function now does ALL the work */
1945 TRACE("Dir %s ...\n",debugstr_w(name));
James Hawkins8cedb212007-03-29 02:38:57 -05001946 path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001947 TRACE("resolves to %s\n",debugstr_w(path));
Mike McCormackee034ba2005-09-20 11:59:14 +00001948 msi_free(path);
Aric Stewart443ad4d2005-06-21 20:50:12 +00001949
1950 return ERROR_SUCCESS;
1951}
1952
1953static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1954{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01001955 MSIPACKAGE *package = param;
Mike McCormack1da28582005-08-22 14:09:17 +00001956 LPCWSTR name;
1957 MSIFEATURE *feature;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001958
Mike McCormack1da28582005-08-22 14:09:17 +00001959 name = MSI_RecordGetString( row, 1 );
Aric Stewart443ad4d2005-06-21 20:50:12 +00001960
Mike McCormack1da28582005-08-22 14:09:17 +00001961 feature = get_loaded_feature( package, name );
1962 if (!feature)
1963 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
Aric Stewart443ad4d2005-06-21 20:50:12 +00001964 else
1965 {
1966 LPCWSTR Condition;
1967 Condition = MSI_RecordGetString(row,3);
1968
Aric Stewart0713f092005-06-24 11:51:29 +00001969 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
Aric Stewart443ad4d2005-06-21 20:50:12 +00001970 {
1971 int level = MSI_RecordGetInteger(row,2);
Francois Gouget633ee952008-05-06 20:01:59 +02001972 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
Mike McCormack1da28582005-08-22 14:09:17 +00001973 feature->Level = level;
Aric Stewart443ad4d2005-06-21 20:50:12 +00001974 }
1975 }
1976 return ERROR_SUCCESS;
1977}
1978
Hans Leidekker82fdc922010-04-27 13:30:32 +02001979static LPWSTR get_disk_file_version( LPCWSTR filename )
Mike McCormackd1723de2006-10-24 17:37:26 +09001980{
1981 static const WCHAR name_fmt[] =
1982 {'%','u','.','%','u','.','%','u','.','%','u',0};
Dmitry Timoshkov76d6b762008-05-26 13:06:47 +09001983 static const WCHAR name[] = {'\\',0};
Mike McCormackd1723de2006-10-24 17:37:26 +09001984 VS_FIXEDFILEINFO *lpVer;
1985 WCHAR filever[0x100];
1986 LPVOID version;
1987 DWORD versize;
1988 DWORD handle;
1989 UINT sz;
1990
1991 TRACE("%s\n", debugstr_w(filename));
1992
1993 versize = GetFileVersionInfoSizeW( filename, &handle );
1994 if (!versize)
1995 return NULL;
1996
1997 version = msi_alloc( versize );
1998 GetFileVersionInfoW( filename, 0, versize, version );
1999
Rob Shearman9c6fac62007-06-26 22:22:52 +01002000 if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
2001 {
2002 msi_free( version );
2003 return NULL;
2004 }
Mike McCormackd1723de2006-10-24 17:37:26 +09002005
2006 sprintfW( filever, name_fmt,
2007 HIWORD(lpVer->dwFileVersionMS),
2008 LOWORD(lpVer->dwFileVersionMS),
2009 HIWORD(lpVer->dwFileVersionLS),
2010 LOWORD(lpVer->dwFileVersionLS));
2011
Rob Shearman023383a2007-06-26 22:23:30 +01002012 msi_free( version );
2013
Mike McCormackd1723de2006-10-24 17:37:26 +09002014 return strdupW( filever );
2015}
2016
Hans Leidekker82fdc922010-04-27 13:30:32 +02002017static DWORD get_disk_file_size( LPCWSTR filename )
2018{
2019 HANDLE file;
2020 DWORD size;
2021
2022 TRACE("%s\n", debugstr_w(filename));
2023
2024 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
2025 if (file == INVALID_HANDLE_VALUE)
2026 return INVALID_FILE_SIZE;
2027
2028 size = GetFileSize( file, NULL );
2029 CloseHandle( file );
2030 return size;
2031}
2032
2033static BOOL hash_matches( MSIFILE *file )
2034{
2035 UINT r;
2036 MSIFILEHASHINFO hash;
2037
2038 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
2039 r = MsiGetFileHashW( file->TargetPath, 0, &hash );
2040 if (r != ERROR_SUCCESS)
2041 return FALSE;
2042
2043 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
2044}
2045
2046static UINT set_file_install_states( MSIPACKAGE *package )
Aric Stewart401bd3f2004-06-28 20:34:35 +00002047{
Mike McCormackc5c55212006-11-07 15:05:48 +09002048 LPWSTR file_version;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002049 MSIFILE *file;
Aric Stewartec688fb2004-07-04 00:35:52 +00002050
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002051 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartec688fb2004-07-04 00:35:52 +00002052 {
Mike McCormackf11c8b02005-09-09 14:48:51 +00002053 MSICOMPONENT* comp = file->Component;
Hans Leidekker82fdc922010-04-27 13:30:32 +02002054 DWORD file_size;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002055 LPWSTR p;
Aric Stewartec688fb2004-07-04 00:35:52 +00002056
Mike McCormackf11c8b02005-09-09 14:48:51 +00002057 if (!comp)
2058 continue;
Aric Stewartec688fb2004-07-04 00:35:52 +00002059
James Hawkinsd893cb72006-09-20 19:55:01 -07002060 if (file->IsCompressed)
James Hawkinsd893cb72006-09-20 19:55:01 -07002061 comp->ForceLocalState = TRUE;
James Hawkinsd893cb72006-09-20 19:55:01 -07002062
Mike McCormackf11c8b02005-09-09 14:48:51 +00002063 /* calculate target */
James Hawkins8cedb212007-03-29 02:38:57 -05002064 p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002065
Mike McCormackee034ba2005-09-20 11:59:14 +00002066 msi_free(file->TargetPath);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002067
2068 TRACE("file %s is named %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09002069 debugstr_w(file->File), debugstr_w(file->FileName));
Mike McCormackf11c8b02005-09-09 14:48:51 +00002070
2071 file->TargetPath = build_directory_name(2, p, file->FileName);
2072
Mike McCormackee034ba2005-09-20 11:59:14 +00002073 msi_free(p);
Mike McCormackf11c8b02005-09-09 14:48:51 +00002074
2075 TRACE("file %s resolves to %s\n",
Mike McCormackd1723de2006-10-24 17:37:26 +09002076 debugstr_w(file->File), debugstr_w(file->TargetPath));
Mike McCormackf11c8b02005-09-09 14:48:51 +00002077
2078 if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
Aric Stewartec688fb2004-07-04 00:35:52 +00002079 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002080 file->state = msifs_missing;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002081 comp->Cost += file->FileSize;
2082 continue;
2083 }
Hans Leidekker82fdc922010-04-27 13:30:32 +02002084 if (file->Version && (file_version = get_disk_file_version( file->TargetPath )))
Mike McCormackf11c8b02005-09-09 14:48:51 +00002085 {
Hans Leidekker82fdc922010-04-27 13:30:32 +02002086 TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(file_version));
2087
2088 if (strcmpiW(file_version, file->Version) < 0)
Aric Stewartec688fb2004-07-04 00:35:52 +00002089 {
Mike McCormackdded8fb2005-11-02 10:56:42 +00002090 file->state = msifs_overwrite;
Aric Stewartec688fb2004-07-04 00:35:52 +00002091 comp->Cost += file->FileSize;
2092 }
2093 else
Hans Leidekker82fdc922010-04-27 13:30:32 +02002094 {
2095 TRACE("Destination file version equal or greater, not overwriting\n");
Mike McCormackdded8fb2005-11-02 10:56:42 +00002096 file->state = msifs_present;
Hans Leidekker82fdc922010-04-27 13:30:32 +02002097 }
Mike McCormackd1723de2006-10-24 17:37:26 +09002098 msi_free( file_version );
Hans Leidekker82fdc922010-04-27 13:30:32 +02002099 continue;
Mike McCormackf11c8b02005-09-09 14:48:51 +00002100 }
Hans Leidekker82fdc922010-04-27 13:30:32 +02002101 if ((file_size = get_disk_file_size( file->TargetPath )) != file->FileSize)
Hans Leidekker9a9faef2010-04-19 12:38:30 +02002102 {
2103 file->state = msifs_overwrite;
Hans Leidekker82fdc922010-04-27 13:30:32 +02002104 comp->Cost += file->FileSize - file_size;
2105 continue;
Hans Leidekker9a9faef2010-04-19 12:38:30 +02002106 }
Hans Leidekker82fdc922010-04-27 13:30:32 +02002107 if (file->hash.dwFileHashInfoSize && hash_matches( file ))
2108 {
2109 TRACE("File hashes match, not overwriting\n");
2110 file->state = msifs_present;
2111 continue;
2112 }
2113 file->state = msifs_overwrite;
2114 comp->Cost += file->FileSize - file_size;
Aric Stewartec688fb2004-07-04 00:35:52 +00002115 }
2116
Mike McCormackc5c55212006-11-07 15:05:48 +09002117 return ERROR_SUCCESS;
2118}
2119
2120/*
2121 * A lot is done in this function aside from just the costing.
2122 * The costing needs to be implemented at some point but for now I am going
2123 * to focus on the directory building
2124 *
2125 */
2126static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2127{
2128 static const WCHAR ExecSeqQuery[] =
2129 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2130 '`','D','i','r','e','c','t','o','r','y','`',0};
2131 static const WCHAR ConditionQuery[] =
2132 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2133 '`','C','o','n','d','i','t','i','o','n','`',0};
2134 static const WCHAR szCosting[] =
2135 {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2136 static const WCHAR szlevel[] =
2137 {'I','N','S','T','A','L','L','L','E','V','E','L',0};
James Hawkinsece5a042008-05-13 20:31:44 -05002138 static const WCHAR szOutOfDiskSpace[] =
2139 {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
Mike McCormackc5c55212006-11-07 15:05:48 +09002140 MSICOMPONENT *comp;
Hans Leidekker0d770c92010-01-27 11:18:02 +01002141 UINT rc = ERROR_SUCCESS;
Mike McCormackc5c55212006-11-07 15:05:48 +09002142 MSIQUERY * view;
2143 LPWSTR level;
2144
Mike McCormackc5c55212006-11-07 15:05:48 +09002145 TRACE("Building Directory properties\n");
2146
2147 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2148 if (rc == ERROR_SUCCESS)
2149 {
2150 rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
2151 package);
2152 msiobj_release(&view->hdr);
2153 }
2154
2155 /* read components states from the registry */
2156 ACTION_GetComponentInstallStates(package);
James Hawkins5a3c3b62008-08-18 23:14:53 -05002157 ACTION_GetFeatureInstallStates(package);
Mike McCormackc5c55212006-11-07 15:05:48 +09002158
Hans Leidekker82fdc922010-04-27 13:30:32 +02002159 TRACE("Calculating file install states\n");
2160 set_file_install_states( package );
Mike McCormackc5c55212006-11-07 15:05:48 +09002161
Hans Leidekker186f4ef2010-04-21 11:37:54 +02002162 if (!process_overrides( package, msi_get_property_int( package->db, szlevel, 1 ) ))
Aric Stewart84837d92004-07-20 01:22:37 +00002163 {
Hans Leidekker9af488d2010-04-27 13:30:10 +02002164 TRACE("Evaluating feature conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002165
Hans Leidekker0d770c92010-01-27 11:18:02 +01002166 rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view );
2167 if (rc == ERROR_SUCCESS)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002168 {
Hans Leidekker0d770c92010-01-27 11:18:02 +01002169 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2170 msiobj_release( &view->hdr );
Aric Stewart7d3e5972004-07-04 00:36:58 +00002171 }
Hans Leidekker9af488d2010-04-27 13:30:10 +02002172 }
2173 TRACE("Evaluating component conditions\n");
Hans Leidekker0d770c92010-01-27 11:18:02 +01002174
Hans Leidekker9af488d2010-04-27 13:30:10 +02002175 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2176 {
2177 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
Hans Leidekker0d770c92010-01-27 11:18:02 +01002178 {
Hans Leidekker9af488d2010-04-27 13:30:10 +02002179 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2180 comp->Enabled = FALSE;
Hans Leidekker0d770c92010-01-27 11:18:02 +01002181 }
Hans Leidekker9af488d2010-04-27 13:30:10 +02002182 else
2183 comp->Enabled = TRUE;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002184 }
2185
Hans Leidekkere31ee692010-04-21 11:38:40 +02002186 msi_set_property( package->db, szCosting, szOne );
Aric Stewart8cc14a92004-12-27 18:56:30 +00002187 /* set default run level if not set */
Hans Leidekker186f4ef2010-04-21 11:37:54 +02002188 level = msi_dup_property( package->db, szlevel );
Aric Stewart8cc14a92004-12-27 18:56:30 +00002189 if (!level)
Hans Leidekkere31ee692010-04-21 11:38:40 +02002190 msi_set_property( package->db, szlevel, szOne );
Mike McCormackee034ba2005-09-20 11:59:14 +00002191 msi_free(level);
Aric Stewartae1aa322004-12-27 19:02:59 +00002192
James Hawkinsece5a042008-05-13 20:31:44 -05002193 /* FIXME: check volume disk space */
Hans Leidekkere31ee692010-04-21 11:38:40 +02002194 msi_set_property( package->db, szOutOfDiskSpace, szZero );
James Hawkinsece5a042008-05-13 20:31:44 -05002195
James Hawkins7c7f0bb2006-07-19 11:15:37 -07002196 return MSI_SetFeatureStates(package);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002197}
2198
Francois Gougetda8b3dd2005-01-26 21:09:04 +00002199/* OK this value is "interpreted" and then formatted based on the
Aric Stewart6e160f12004-06-29 04:07:22 +00002200 first few characters */
Aric Stewart09b0aba2005-06-09 20:30:59 +00002201static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
Aric Stewart401bd3f2004-06-28 20:34:35 +00002202 DWORD *size)
2203{
2204 LPSTR data = NULL;
James Hawkins2f658cb2008-02-04 19:06:53 -06002205
Aric Stewart6e160f12004-06-29 04:07:22 +00002206 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
Aric Stewart401bd3f2004-06-28 20:34:35 +00002207 {
Aric Stewart6e160f12004-06-29 04:07:22 +00002208 if (value[1]=='x')
2209 {
2210 LPWSTR ptr;
2211 CHAR byte[5];
Aric Stewart6186b2b2005-05-16 21:37:35 +00002212 LPWSTR deformated = NULL;
Aric Stewart6e160f12004-06-29 04:07:22 +00002213 int count;
2214
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002215 deformat_string(package, &value[2], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002216
2217 /* binary value type */
Aric Stewart6186b2b2005-05-16 21:37:35 +00002218 ptr = deformated;
2219 *type = REG_BINARY;
2220 if (strlenW(ptr)%2)
2221 *size = (strlenW(ptr)/2)+1;
2222 else
2223 *size = strlenW(ptr)/2;
2224
Mike McCormackee034ba2005-09-20 11:59:14 +00002225 data = msi_alloc(*size);
Aric Stewart6186b2b2005-05-16 21:37:35 +00002226
Aric Stewart6e160f12004-06-29 04:07:22 +00002227 byte[0] = '0';
2228 byte[1] = 'x';
2229 byte[4] = 0;
2230 count = 0;
Aric Stewart6186b2b2005-05-16 21:37:35 +00002231 /* if uneven pad with a zero in front */
2232 if (strlenW(ptr)%2)
2233 {
2234 byte[2]= '0';
2235 byte[3]= *ptr;
2236 ptr++;
2237 data[count] = (BYTE)strtol(byte,NULL,0);
2238 count ++;
2239 TRACE("Uneven byte count\n");
2240 }
Aric Stewart6e160f12004-06-29 04:07:22 +00002241 while (*ptr)
2242 {
2243 byte[2]= *ptr;
2244 ptr++;
2245 byte[3]= *ptr;
2246 ptr++;
2247 data[count] = (BYTE)strtol(byte,NULL,0);
2248 count ++;
2249 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002250 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002251
Mike McCormackf1d46462006-10-05 13:41:22 +09002252 TRACE("Data %i bytes(%i)\n",*size,count);
Aric Stewart6e160f12004-06-29 04:07:22 +00002253 }
2254 else
2255 {
2256 LPWSTR deformated;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002257 LPWSTR p;
2258 DWORD d = 0;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002259 deformat_string(package, &value[1], &deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002260
2261 *type=REG_DWORD;
2262 *size = sizeof(DWORD);
Mike McCormackee034ba2005-09-20 11:59:14 +00002263 data = msi_alloc(*size);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002264 p = deformated;
2265 if (*p == '-')
2266 p++;
2267 while (*p)
2268 {
2269 if ( (*p < '0') || (*p > '9') )
2270 break;
2271 d *= 10;
2272 d += (*p - '0');
2273 p++;
2274 }
2275 if (deformated[0] == '-')
2276 d = -d;
2277 *(LPDWORD)data = d;
Mike McCormackf1d46462006-10-05 13:41:22 +09002278 TRACE("DWORD %i\n",*(LPDWORD)data);
Aric Stewart6e160f12004-06-29 04:07:22 +00002279
Mike McCormackee034ba2005-09-20 11:59:14 +00002280 msi_free(deformated);
Aric Stewart6e160f12004-06-29 04:07:22 +00002281 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002282 }
2283 else
2284 {
Aric Stewart54c67dd2005-01-25 20:17:09 +00002285 static const WCHAR szMulti[] = {'[','~',']',0};
Aric Stewart09b0aba2005-06-09 20:30:59 +00002286 LPCWSTR ptr;
Aric Stewart6e160f12004-06-29 04:07:22 +00002287 *type=REG_SZ;
2288
Aric Stewart401bd3f2004-06-28 20:34:35 +00002289 if (value[0]=='#')
Aric Stewart6e160f12004-06-29 04:07:22 +00002290 {
2291 if (value[1]=='%')
2292 {
2293 ptr = &value[2];
2294 *type=REG_EXPAND_SZ;
2295 }
2296 else
2297 ptr = &value[1];
2298 }
2299 else
Aric Stewart401bd3f2004-06-28 20:34:35 +00002300 ptr=value;
2301
Aric Stewart54c67dd2005-01-25 20:17:09 +00002302 if (strstrW(value,szMulti))
2303 *type = REG_MULTI_SZ;
2304
James Hawkins2f658cb2008-02-04 19:06:53 -06002305 /* remove initial delimiter */
2306 if (!strncmpW(value, szMulti, 3))
2307 ptr = value + 3;
2308
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002309 *size = deformat_string(package, ptr,(LPWSTR*)&data);
James Hawkins2f658cb2008-02-04 19:06:53 -06002310
2311 /* add double NULL terminator */
2312 if (*type == REG_MULTI_SZ)
2313 {
James Hawkins21b4af12008-02-24 20:15:31 -06002314 *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2315 data = msi_realloc_zero(data, *size);
James Hawkins2f658cb2008-02-04 19:06:53 -06002316 }
Aric Stewart401bd3f2004-06-28 20:34:35 +00002317 }
2318 return data;
2319}
2320
Hans Leidekker342f8662010-02-25 15:17:11 +01002321static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2322{
2323 const WCHAR *ret;
2324
2325 switch (root)
2326 {
2327 case -1:
Hans Leidekker186f4ef2010-04-21 11:37:54 +02002328 if (msi_get_property_int( package->db, szAllUsers, 0 ))
Hans Leidekker342f8662010-02-25 15:17:11 +01002329 {
2330 *root_key = HKEY_LOCAL_MACHINE;
2331 ret = szHLM;
2332 }
2333 else
2334 {
2335 *root_key = HKEY_CURRENT_USER;
2336 ret = szHCU;
2337 }
2338 break;
2339 case 0:
2340 *root_key = HKEY_CLASSES_ROOT;
2341 ret = szHCR;
2342 break;
2343 case 1:
2344 *root_key = HKEY_CURRENT_USER;
2345 ret = szHCU;
2346 break;
2347 case 2:
2348 *root_key = HKEY_LOCAL_MACHINE;
2349 ret = szHLM;
2350 break;
2351 case 3:
2352 *root_key = HKEY_USERS;
2353 ret = szHU;
2354 break;
2355 default:
2356 ERR("Unknown root %i\n", root);
2357 return NULL;
2358 }
2359
2360 return ret;
2361}
2362
Aric Stewart92ef78e2005-06-21 20:21:18 +00002363static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2364{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01002365 MSIPACKAGE *package = param;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002366 LPSTR value_data = NULL;
2367 HKEY root_key, hkey;
2368 DWORD type,size;
2369 LPWSTR deformated;
2370 LPCWSTR szRoot, component, name, key, value;
Mike McCormack38d67a42005-08-22 09:15:23 +00002371 MSICOMPONENT *comp;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002372 MSIRECORD * uirow;
2373 LPWSTR uikey;
2374 INT root;
2375 BOOL check_first = FALSE;
2376 UINT rc;
2377
2378 ui_progress(package,2,0,0,0);
2379
2380 value = NULL;
2381 key = NULL;
2382 uikey = NULL;
2383 name = NULL;
2384
2385 component = MSI_RecordGetString(row, 6);
Mike McCormack38d67a42005-08-22 09:15:23 +00002386 comp = get_loaded_component(package,component);
Johan Dahlin0946c422005-08-24 10:57:27 +00002387 if (!comp)
2388 return ERROR_SUCCESS;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002389
Hans Leidekker598c5422010-02-16 11:44:47 +01002390 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart92ef78e2005-06-21 20:21:18 +00002391 {
Hans Leidekker598c5422010-02-16 11:44:47 +01002392 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00002393 comp->Action = comp->Installed;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002394 return ERROR_SUCCESS;
2395 }
Mike McCormack38d67a42005-08-22 09:15:23 +00002396 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart92ef78e2005-06-21 20:21:18 +00002397
2398 name = MSI_RecordGetString(row, 4);
2399 if( MSI_RecordIsNull(row,5) && name )
2400 {
2401 /* null values can have special meanings */
2402 if (name[0]=='-' && name[1] == 0)
2403 return ERROR_SUCCESS;
2404 else if ((name[0]=='+' && name[1] == 0) ||
2405 (name[0] == '*' && name[1] == 0))
2406 name = NULL;
2407 check_first = TRUE;
2408 }
2409
2410 root = MSI_RecordGetInteger(row,2);
2411 key = MSI_RecordGetString(row, 3);
2412
Hans Leidekker342f8662010-02-25 15:17:11 +01002413 szRoot = get_root_key( package, root, &root_key );
2414 if (!szRoot)
Aric Stewart92ef78e2005-06-21 20:21:18 +00002415 return ERROR_SUCCESS;
2416
2417 deformat_string(package, key , &deformated);
2418 size = strlenW(deformated) + strlenW(szRoot) + 1;
Mike McCormackee034ba2005-09-20 11:59:14 +00002419 uikey = msi_alloc(size*sizeof(WCHAR));
Aric Stewart92ef78e2005-06-21 20:21:18 +00002420 strcpyW(uikey,szRoot);
2421 strcatW(uikey,deformated);
2422
2423 if (RegCreateKeyW( root_key, deformated, &hkey))
2424 {
2425 ERR("Could not create key %s\n",debugstr_w(deformated));
Mike McCormackee034ba2005-09-20 11:59:14 +00002426 msi_free(deformated);
2427 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002428 return ERROR_SUCCESS;
2429 }
Mike McCormackee034ba2005-09-20 11:59:14 +00002430 msi_free(deformated);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002431
2432 value = MSI_RecordGetString(row,5);
2433 if (value)
2434 value_data = parse_value(package, value, &type, &size);
2435 else
2436 {
Aric Stewart92ef78e2005-06-21 20:21:18 +00002437 value_data = (LPSTR)strdupW(szEmpty);
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02002438 size = sizeof(szEmpty);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002439 type = REG_SZ;
2440 }
2441
2442 deformat_string(package, name, &deformated);
2443
Aric Stewart92ef78e2005-06-21 20:21:18 +00002444 if (!check_first)
2445 {
2446 TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2447 debugstr_w(uikey));
Mike McCormack16466af2005-07-06 10:33:30 +00002448 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002449 }
2450 else
2451 {
2452 DWORD sz = 0;
2453 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2454 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2455 {
2456 TRACE("value %s of %s checked already exists\n",
2457 debugstr_w(deformated), debugstr_w(uikey));
2458 }
2459 else
2460 {
2461 TRACE("Checked and setting value %s of %s\n",
2462 debugstr_w(deformated), debugstr_w(uikey));
2463 if (deformated || size)
Mike McCormack16466af2005-07-06 10:33:30 +00002464 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002465 }
2466 }
2467 RegCloseKey(hkey);
2468
2469 uirow = MSI_CreateRecord(3);
2470 MSI_RecordSetStringW(uirow,2,deformated);
2471 MSI_RecordSetStringW(uirow,1,uikey);
Hans Leidekkerd0856c02010-03-23 11:47:42 +01002472 if (type == REG_SZ || type == REG_EXPAND_SZ)
Aric Stewart92ef78e2005-06-21 20:21:18 +00002473 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002474 ui_actiondata(package,szWriteRegistryValues,uirow);
2475 msiobj_release( &uirow->hdr );
2476
Mike McCormackee034ba2005-09-20 11:59:14 +00002477 msi_free(value_data);
2478 msi_free(deformated);
2479 msi_free(uikey);
Aric Stewart92ef78e2005-06-21 20:21:18 +00002480
2481 return ERROR_SUCCESS;
2482}
2483
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002484static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
Aric Stewart401bd3f2004-06-28 20:34:35 +00002485{
2486 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002487 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00002488 static const WCHAR ExecSeqQuery[] =
2489 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002490 '`','R','e','g','i','s','t','r','y','`',0 };
Aric Stewart401bd3f2004-06-28 20:34:35 +00002491
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002492 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002493 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002494 return ERROR_SUCCESS;
Aric Stewart401bd3f2004-06-28 20:34:35 +00002495
Aric Stewartd2c395a2004-07-06 18:48:15 +00002496 /* increment progress bar each time action data is sent */
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002497 ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002498
Aric Stewart92ef78e2005-06-21 20:21:18 +00002499 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
Aric Stewartd2c395a2004-07-06 18:48:15 +00002500
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002501 msiobj_release(&view->hdr);
Aric Stewart401bd3f2004-06-28 20:34:35 +00002502 return rc;
2503}
2504
Hans Leidekker342f8662010-02-25 15:17:11 +01002505static void delete_reg_key_or_value( HKEY hkey_root, LPCWSTR key, LPCWSTR value, BOOL delete_key )
2506{
2507 LONG res;
2508 HKEY hkey;
2509 DWORD num_subkeys, num_values;
2510
2511 if (delete_key)
2512 {
2513 if ((res = RegDeleteTreeW( hkey_root, key )))
2514 {
2515 WARN("Failed to delete key %s (%d)\n", debugstr_w(key), res);
2516 }
2517 return;
2518 }
2519
2520 if (!(res = RegOpenKeyW( hkey_root, key, &hkey )))
2521 {
2522 if ((res = RegDeleteValueW( hkey, value )))
2523 {
2524 WARN("Failed to delete value %s (%d)\n", debugstr_w(value), res);
2525 }
2526 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values,
2527 NULL, NULL, NULL, NULL );
2528 RegCloseKey( hkey );
2529
2530 if (!res && !num_subkeys && !num_values)
2531 {
2532 TRACE("Removing empty key %s\n", debugstr_w(key));
2533 RegDeleteKeyW( hkey_root, key );
2534 }
2535 return;
2536 }
2537 WARN("Failed to open key %s (%d)\n", debugstr_w(key), res);
2538}
2539
2540
2541static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2542{
2543 MSIPACKAGE *package = param;
2544 LPCWSTR component, name, key_str, root_key_str;
2545 LPWSTR deformated_key, deformated_name, ui_key_str;
2546 MSICOMPONENT *comp;
2547 MSIRECORD *uirow;
2548 BOOL delete_key = FALSE;
2549 HKEY hkey_root;
2550 UINT size;
2551 INT root;
2552
2553 ui_progress( package, 2, 0, 0, 0 );
2554
2555 component = MSI_RecordGetString( row, 6 );
2556 comp = get_loaded_component( package, component );
2557 if (!comp)
2558 return ERROR_SUCCESS;
2559
2560 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
2561 {
2562 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
2563 comp->Action = comp->Installed;
2564 return ERROR_SUCCESS;
2565 }
2566 comp->Action = INSTALLSTATE_ABSENT;
2567
2568 name = MSI_RecordGetString( row, 4 );
2569 if (MSI_RecordIsNull( row, 5 ) && name )
2570 {
2571 if (name[0] == '+' && !name[1])
2572 return ERROR_SUCCESS;
2573 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1]))
2574 {
2575 delete_key = TRUE;
2576 name = NULL;
2577 }
2578 }
2579
2580 root = MSI_RecordGetInteger( row, 2 );
2581 key_str = MSI_RecordGetString( row, 3 );
2582
2583 root_key_str = get_root_key( package, root, &hkey_root );
2584 if (!root_key_str)
2585 return ERROR_SUCCESS;
2586
2587 deformat_string( package, key_str, &deformated_key );
2588 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2589 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2590 strcpyW( ui_key_str, root_key_str );
2591 strcatW( ui_key_str, deformated_key );
2592
2593 deformat_string( package, name, &deformated_name );
2594
2595 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2596 msi_free( deformated_key );
2597
2598 uirow = MSI_CreateRecord( 2 );
2599 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2600 MSI_RecordSetStringW( uirow, 2, deformated_name );
2601
2602 ui_actiondata( package, szRemoveRegistryValues, uirow );
2603 msiobj_release( &uirow->hdr );
2604
2605 msi_free( ui_key_str );
2606 msi_free( deformated_name );
2607 return ERROR_SUCCESS;
2608}
2609
2610static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2611{
2612 MSIPACKAGE *package = param;
2613 LPCWSTR component, name, key_str, root_key_str;
2614 LPWSTR deformated_key, deformated_name, ui_key_str;
2615 MSICOMPONENT *comp;
2616 MSIRECORD *uirow;
2617 BOOL delete_key = FALSE;
2618 HKEY hkey_root;
2619 UINT size;
2620 INT root;
2621
2622 ui_progress( package, 2, 0, 0, 0 );
2623
2624 component = MSI_RecordGetString( row, 5 );
2625 comp = get_loaded_component( package, component );
2626 if (!comp)
2627 return ERROR_SUCCESS;
2628
2629 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
2630 {
2631 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
2632 comp->Action = comp->Installed;
2633 return ERROR_SUCCESS;
2634 }
2635 comp->Action = INSTALLSTATE_LOCAL;
2636
2637 if ((name = MSI_RecordGetString( row, 4 )))
2638 {
2639 if (name[0] == '-' && !name[1])
2640 {
2641 delete_key = TRUE;
2642 name = NULL;
2643 }
2644 }
2645
2646 root = MSI_RecordGetInteger( row, 2 );
2647 key_str = MSI_RecordGetString( row, 3 );
2648
2649 root_key_str = get_root_key( package, root, &hkey_root );
2650 if (!root_key_str)
2651 return ERROR_SUCCESS;
2652
2653 deformat_string( package, key_str, &deformated_key );
2654 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
2655 ui_key_str = msi_alloc( size * sizeof(WCHAR) );
2656 strcpyW( ui_key_str, root_key_str );
2657 strcatW( ui_key_str, deformated_key );
2658
2659 deformat_string( package, name, &deformated_name );
2660
2661 delete_reg_key_or_value( hkey_root, deformated_key, deformated_name, delete_key );
2662 msi_free( deformated_key );
2663
2664 uirow = MSI_CreateRecord( 2 );
2665 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2666 MSI_RecordSetStringW( uirow, 2, deformated_name );
2667
2668 ui_actiondata( package, szRemoveRegistryValues, uirow );
2669 msiobj_release( &uirow->hdr );
2670
2671 msi_free( ui_key_str );
2672 msi_free( deformated_name );
2673 return ERROR_SUCCESS;
2674}
2675
2676static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
2677{
2678 UINT rc;
2679 MSIQUERY *view;
2680 static const WCHAR registry_query[] =
2681 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2682 '`','R','e','g','i','s','t','r','y','`',0 };
2683 static const WCHAR remove_registry_query[] =
2684 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2685 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
2686
2687 /* increment progress bar each time action data is sent */
2688 ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
2689
2690 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
2691 if (rc == ERROR_SUCCESS)
2692 {
2693 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
2694 msiobj_release( &view->hdr );
2695 if (rc != ERROR_SUCCESS)
2696 return rc;
2697 }
2698
2699 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
2700 if (rc == ERROR_SUCCESS)
2701 {
2702 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
2703 msiobj_release( &view->hdr );
2704 if (rc != ERROR_SUCCESS)
2705 return rc;
2706 }
2707
2708 return ERROR_SUCCESS;
2709}
2710
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002711static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002712{
Aric Stewart9cd707d2005-05-27 19:24:22 +00002713 package->script->CurrentlyScripting = TRUE;
2714
Aric Stewart7d3e5972004-07-04 00:36:58 +00002715 return ERROR_SUCCESS;
2716}
2717
Aric Stewartae1aa322004-12-27 19:02:59 +00002718
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002719static UINT ACTION_InstallValidate(MSIPACKAGE *package)
Aric Stewart7d3e5972004-07-04 00:36:58 +00002720{
Mike McCormack38d67a42005-08-22 09:15:23 +00002721 MSICOMPONENT *comp;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002722 DWORD progress = 0;
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002723 DWORD total = 0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002724 static const WCHAR q1[]=
2725 {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002726 '`','R','e','g','i','s','t','r','y','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002727 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002728 MSIQUERY * view;
Mike McCormack1da28582005-08-22 14:09:17 +00002729 MSIFEATURE *feature;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002730 MSIFILE *file;
Aric Stewart7d3e5972004-07-04 00:36:58 +00002731
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002732 TRACE("InstallValidate\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002733
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002734 rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002735 if (rc == ERROR_SUCCESS)
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002736 {
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002737 MSI_IterateRecords( view, &progress, NULL, package );
2738 msiobj_release( &view->hdr );
2739 total += progress * REG_PROGRESS_VALUE;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002740 }
Aric Stewart7d3e5972004-07-04 00:36:58 +00002741
Mike McCormack38d67a42005-08-22 09:15:23 +00002742 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Mike McCormack38d67a42005-08-22 09:15:23 +00002743 total += COMPONENT_PROGRESS_VALUE;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002744
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002745 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002746 total += file->FileSize;
Mike McCormackf3f12ab2005-09-21 10:20:03 +00002747
Aric Stewartbd1bbc12005-01-03 20:00:13 +00002748 ui_progress(package,0,total,0,0);
Aric Stewart7d3e5972004-07-04 00:36:58 +00002749
Mike McCormack1da28582005-08-22 14:09:17 +00002750 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002751 {
Aric Stewartb39d8fc2005-05-13 13:56:39 +00002752 TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2753 debugstr_w(feature->Feature), feature->Installed, feature->Action,
2754 feature->ActionRequest);
2755 }
2756
Aric Stewart7d3e5972004-07-04 00:36:58 +00002757 return ERROR_SUCCESS;
2758}
2759
Aric Stewartc79f4e22005-06-22 18:03:08 +00002760static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2761{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01002762 MSIPACKAGE* package = param;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002763 LPCWSTR cond = NULL;
2764 LPCWSTR message = NULL;
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002765 UINT r;
2766
Aric Stewartc79f4e22005-06-22 18:03:08 +00002767 static const WCHAR title[]=
2768 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2769
2770 cond = MSI_RecordGetString(row,1);
2771
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002772 r = MSI_EvaluateConditionW(package,cond);
2773 if (r == MSICONDITION_FALSE)
Aric Stewartc79f4e22005-06-22 18:03:08 +00002774 {
James Hawkinsbafc4dc2007-06-28 15:38:58 -07002775 if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2776 {
2777 LPWSTR deformated;
2778 message = MSI_RecordGetString(row,2);
2779 deformat_string(package,message,&deformated);
2780 MessageBoxW(NULL,deformated,title,MB_OK);
2781 msi_free(deformated);
2782 }
2783
2784 return ERROR_INSTALL_FAILURE;
Aric Stewartc79f4e22005-06-22 18:03:08 +00002785 }
2786
2787 return ERROR_SUCCESS;
2788}
2789
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002790static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
Aric Stewart5b936ca2004-07-06 18:47:09 +00002791{
2792 UINT rc;
Mike McCormackf3c8b832004-07-19 19:35:05 +00002793 MSIQUERY * view = NULL;
Aric Stewart8e233e92005-03-01 11:45:19 +00002794 static const WCHAR ExecSeqQuery[] =
2795 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002796 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
Aric Stewart7d3e5972004-07-04 00:36:58 +00002797
Aric Stewart5b936ca2004-07-06 18:47:09 +00002798 TRACE("Checking launch conditions\n");
Aric Stewart7d3e5972004-07-04 00:36:58 +00002799
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002800 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
Aric Stewart5b936ca2004-07-06 18:47:09 +00002801 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00002802 return ERROR_SUCCESS;
Aric Stewart5b936ca2004-07-06 18:47:09 +00002803
Aric Stewartc79f4e22005-06-22 18:03:08 +00002804 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002805 msiobj_release(&view->hdr);
Aric Stewartc79f4e22005-06-22 18:03:08 +00002806
Aric Stewart5b936ca2004-07-06 18:47:09 +00002807 return rc;
2808}
Aric Stewart7d3e5972004-07-04 00:36:58 +00002809
Mike McCormack38d67a42005-08-22 09:15:23 +00002810static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
Aric Stewartb942e182004-07-06 18:50:02 +00002811{
Aric Stewartb942e182004-07-06 18:50:02 +00002812
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002813 if (!cmp->KeyPath)
James Hawkins8cedb212007-03-29 02:38:57 -05002814 return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002815
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002816 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
Aric Stewartb942e182004-07-06 18:50:02 +00002817 {
Aric Stewart6269f002005-01-17 13:40:39 +00002818 MSIRECORD * row = 0;
Mike McCormack0b352c72005-06-02 10:29:57 +00002819 UINT root,len;
Aric Stewart09b0aba2005-06-09 20:30:59 +00002820 LPWSTR deformated,buffer,deformated_name;
2821 LPCWSTR key,name;
Aric Stewart8e233e92005-03-01 11:45:19 +00002822 static const WCHAR ExecSeqQuery[] =
2823 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00002824 '`','R','e','g','i','s','t','r','y','`',' ',
2825 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2826 ' ','=',' ' ,'\'','%','s','\'',0 };
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002827 static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
Aric Stewart8e233e92005-03-01 11:45:19 +00002828 static const WCHAR fmt2[]=
2829 {'%','0','2','i',':','\\','%','s','\\','%','s',0};
Aric Stewart6269f002005-01-17 13:40:39 +00002830
Mike McCormack0b352c72005-06-02 10:29:57 +00002831 row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2832 if (!row)
Aric Stewart6269f002005-01-17 13:40:39 +00002833 return NULL;
2834
Aric Stewart6269f002005-01-17 13:40:39 +00002835 root = MSI_RecordGetInteger(row,2);
Aric Stewart09b0aba2005-06-09 20:30:59 +00002836 key = MSI_RecordGetString(row, 3);
2837 name = MSI_RecordGetString(row, 4);
Aric Stewart6269f002005-01-17 13:40:39 +00002838 deformat_string(package, key , &deformated);
2839 deformat_string(package, name, &deformated_name);
2840
Ulrich Czekallae15e5172005-03-08 16:44:51 +00002841 len = strlenW(deformated) + 6;
Aric Stewart6269f002005-01-17 13:40:39 +00002842 if (deformated_name)
2843 len+=strlenW(deformated_name);
2844
Mike McCormackee034ba2005-09-20 11:59:14 +00002845 buffer = msi_alloc( len *sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00002846
2847 if (deformated_name)
2848 sprintfW(buffer,fmt2,root,deformated,deformated_name);
2849 else
2850 sprintfW(buffer,fmt,root,deformated);
2851
Mike McCormackee034ba2005-09-20 11:59:14 +00002852 msi_free(deformated);
2853 msi_free(deformated_name);
Aric Stewart6269f002005-01-17 13:40:39 +00002854 msiobj_release(&row->hdr);
Aric Stewart6269f002005-01-17 13:40:39 +00002855
2856 return buffer;
2857 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002858 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewart6269f002005-01-17 13:40:39 +00002859 {
2860 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
Aric Stewartfa384f62004-12-22 18:46:17 +00002861 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002862 }
2863 else
2864 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002865 MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
Aric Stewartfcb20c52004-07-06 18:51:16 +00002866
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002867 if (file)
2868 return strdupW( file->TargetPath );
Aric Stewartb942e182004-07-06 18:50:02 +00002869 }
Aric Stewartfa384f62004-12-22 18:46:17 +00002870 return NULL;
Aric Stewartb942e182004-07-06 18:50:02 +00002871}
2872
Stefan Huehnerac6f5622005-06-20 14:18:03 +00002873static HKEY openSharedDLLsKey(void)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002874{
2875 HKEY hkey=0;
Aric Stewart8e233e92005-03-01 11:45:19 +00002876 static const WCHAR path[] =
2877 {'S','o','f','t','w','a','r','e','\\',
2878 'M','i','c','r','o','s','o','f','t','\\',
2879 'W','i','n','d','o','w','s','\\',
2880 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2881 'S','h','a','r','e','d','D','L','L','s',0};
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002882
2883 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2884 return hkey;
2885}
2886
2887static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2888{
2889 HKEY hkey;
2890 DWORD count=0;
2891 DWORD type;
2892 DWORD sz = sizeof(count);
2893 DWORD rc;
2894
2895 hkey = openSharedDLLsKey();
2896 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2897 if (rc != ERROR_SUCCESS)
2898 count = 0;
2899 RegCloseKey(hkey);
2900 return count;
2901}
2902
2903static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2904{
2905 HKEY hkey;
2906
2907 hkey = openSharedDLLsKey();
2908 if (count > 0)
Mike McCormack4db02cd2005-09-15 14:58:38 +00002909 msi_reg_set_val_dword( hkey, path, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002910 else
2911 RegDeleteValueW(hkey,path);
2912 RegCloseKey(hkey);
2913 return count;
2914}
2915
2916/*
2917 * Return TRUE if the count should be written out and FALSE if not
2918 */
Mike McCormack38d67a42005-08-22 09:15:23 +00002919static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002920{
Mike McCormack1da28582005-08-22 14:09:17 +00002921 MSIFEATURE *feature;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002922 INT count = 0;
2923 BOOL write = FALSE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002924
2925 /* only refcount DLLs */
Mike McCormackefcc1ec2005-09-12 12:07:15 +00002926 if (comp->KeyPath == NULL ||
Mike McCormack38d67a42005-08-22 09:15:23 +00002927 comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
2928 comp->Attributes & msidbComponentAttributesODBCDataSource)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002929 write = FALSE;
2930 else
2931 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002932 count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002933 write = (count > 0);
2934
Mike McCormack38d67a42005-08-22 09:15:23 +00002935 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002936 write = TRUE;
2937 }
2938
2939 /* increment counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002940 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002941 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002942 ComponentList *cl;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002943
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01002944 if (feature->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002945 continue;
2946
Mike McCormack1da28582005-08-22 14:09:17 +00002947 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002948 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002949 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002950 count++;
2951 }
2952 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002953
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002954 /* decrement counts */
Mike McCormack1da28582005-08-22 14:09:17 +00002955 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002956 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00002957 ComponentList *cl;
2958
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01002959 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002960 continue;
2961
Mike McCormack1da28582005-08-22 14:09:17 +00002962 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002963 {
Mike McCormack38d67a42005-08-22 09:15:23 +00002964 if ( cl->component == comp )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002965 count--;
2966 }
2967 }
2968
2969 /* ref count all the files in the component */
2970 if (write)
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002971 {
2972 MSIFILE *file;
2973
2974 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002975 {
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002976 if (file->Component == comp)
2977 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002978 }
Mike McCormacke18f8ab2005-08-23 10:03:17 +00002979 }
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002980
Austin English5644f052008-04-07 14:44:23 -05002981 /* add a count for permanent */
Mike McCormack38d67a42005-08-22 09:15:23 +00002982 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002983 count ++;
2984
Mike McCormack38d67a42005-08-22 09:15:23 +00002985 comp->RefCount = count;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002986
2987 if (write)
Mike McCormack38d67a42005-08-22 09:15:23 +00002988 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00002989}
2990
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00002991static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
Aric Stewartb942e182004-07-06 18:50:02 +00002992{
Aric Stewart68b07492005-01-25 11:05:37 +00002993 WCHAR squished_pc[GUID_SIZE];
2994 WCHAR squished_cc[GUID_SIZE];
Aric Stewartb942e182004-07-06 18:50:02 +00002995 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00002996 MSICOMPONENT *comp;
James Hawkins4aa3a992008-06-18 00:49:42 -05002997 HKEY hkey;
Aric Stewartb942e182004-07-06 18:50:02 +00002998
James Hawkinsfc6b9dd2007-11-01 03:12:41 -05002999 TRACE("\n");
3000
Aric Stewartadaef112005-07-07 20:27:06 +00003001 squash_guid(package->ProductCode,squished_pc);
Aric Stewartbd1bbc12005-01-03 20:00:13 +00003002 ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
Mike McCormack38d67a42005-08-22 09:15:23 +00003003
3004 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
Aric Stewartb942e182004-07-06 18:50:02 +00003005 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09003006 MSIRECORD * uirow;
3007
Aric Stewartbd1bbc12005-01-03 20:00:13 +00003008 ui_progress(package,2,0,0,0);
Mike McCormackfe8cd382006-03-09 14:21:37 +09003009 if (!comp->ComponentId)
3010 continue;
Aric Stewartb942e182004-07-06 18:50:02 +00003011
Mike McCormackfe8cd382006-03-09 14:21:37 +09003012 squash_guid(comp->ComponentId,squished_cc);
Mike McCormacka3a2eae2006-11-29 16:36:58 +09003013
Mike McCormackfe8cd382006-03-09 14:21:37 +09003014 msi_free(comp->FullKeypath);
3015 comp->FullKeypath = resolve_keypath( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003016
Mike McCormackfe8cd382006-03-09 14:21:37 +09003017 ACTION_RefCountComponent( package, comp );
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003018
Mike McCormackfe8cd382006-03-09 14:21:37 +09003019 TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
Mike McCormack38d67a42005-08-22 09:15:23 +00003020 debugstr_w(comp->Component),
Aric Stewartc5a14432005-05-18 17:46:12 +00003021 debugstr_w(squished_cc),
Mike McCormackfe8cd382006-03-09 14:21:37 +09003022 debugstr_w(comp->FullKeypath),
Mike McCormack38d67a42005-08-22 09:15:23 +00003023 comp->RefCount);
James Hawkins96dd6ce2008-08-21 02:14:26 -05003024
Hans Leidekker598c5422010-02-16 11:44:47 +01003025 if (comp->ActionRequest == INSTALLSTATE_LOCAL ||
3026 comp->ActionRequest == INSTALLSTATE_SOURCE)
Mike McCormackfe8cd382006-03-09 14:21:37 +09003027 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09003028 if (!comp->FullKeypath)
3029 continue;
3030
James Hawkins288af812008-06-18 00:51:13 -05003031 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
James Hawkinsb198f4f2008-12-09 00:21:00 -06003032 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
3033 &hkey, TRUE);
James Hawkins288af812008-06-18 00:51:13 -05003034 else
James Hawkinsb198f4f2008-12-09 00:21:00 -06003035 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
3036 &hkey, TRUE);
James Hawkins288af812008-06-18 00:51:13 -05003037
James Hawkins4aa3a992008-06-18 00:49:42 -05003038 if (rc != ERROR_SUCCESS)
3039 continue;
Mike McCormackfe8cd382006-03-09 14:21:37 +09003040
3041 if (comp->Attributes & msidbComponentAttributesPermanent)
Aric Stewartfa384f62004-12-22 18:46:17 +00003042 {
Mike McCormackfe8cd382006-03-09 14:21:37 +09003043 static const WCHAR szPermKey[] =
3044 { '0','0','0','0','0','0','0','0','0','0','0','0',
3045 '0','0','0','0','0','0','0','0','0','0','0','0',
3046 '0','0','0','0','0','0','0','0',0 };
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003047
James Hawkins4aa3a992008-06-18 00:49:42 -05003048 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00003049 }
Aric Stewartb39d8fc2005-05-13 13:56:39 +00003050
James Hawkins96dd6ce2008-08-21 02:14:26 -05003051 if (comp->Action == INSTALLSTATE_LOCAL)
3052 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
3053 else
3054 {
3055 MSIFILE *file;
3056 MSIRECORD *row;
3057 LPWSTR ptr, ptr2;
3058 WCHAR source[MAX_PATH];
3059 WCHAR base[MAX_PATH];
James Hawkinsd15fddf2008-10-06 22:26:20 -05003060 LPWSTR sourcepath;
James Hawkins96dd6ce2008-08-21 02:14:26 -05003061
3062 static const WCHAR fmt[] = {'%','0','2','d','\\',0};
3063 static const WCHAR query[] = {
3064 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3065 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3066 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
3067 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
3068 '`','D','i','s','k','I','d','`',0};
3069
3070 file = get_loaded_file(package, comp->KeyPath);
3071 if (!file)
3072 continue;
3073
3074 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3075 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3076 ptr2 = strrchrW(source, '\\') + 1;
3077 msiobj_release(&row->hdr);
3078
3079 lstrcpyW(base, package->PackagePath);
3080 ptr = strrchrW(base, '\\');
3081 *(ptr + 1) = '\0';
3082
James Hawkinsd15fddf2008-10-06 22:26:20 -05003083 sourcepath = resolve_file_source(package, file);
3084 ptr = sourcepath + lstrlenW(base);
James Hawkins96dd6ce2008-08-21 02:14:26 -05003085 lstrcpyW(ptr2, ptr);
James Hawkinsd15fddf2008-10-06 22:26:20 -05003086 msi_free(sourcepath);
James Hawkins96dd6ce2008-08-21 02:14:26 -05003087
3088 msi_reg_set_val_str(hkey, squished_pc, source);
3089 }
James Hawkins4aa3a992008-06-18 00:49:42 -05003090 RegCloseKey(hkey);
Mike McCormackfe8cd382006-03-09 14:21:37 +09003091 }
Hans Leidekker598c5422010-02-16 11:44:47 +01003092 else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
James Hawkins288af812008-06-18 00:51:13 -05003093 {
3094 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
James Hawkinsa9e02902008-12-09 00:21:19 -06003095 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
James Hawkins288af812008-06-18 00:51:13 -05003096 else
James Hawkinsa9e02902008-12-09 00:21:19 -06003097 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
James Hawkins288af812008-06-18 00:51:13 -05003098 }
Hans Leidekker27e90272010-03-23 11:46:24 +01003099 comp->Action = comp->ActionRequest;
Mike McCormacka3a2eae2006-11-29 16:36:58 +09003100
3101 /* UI stuff */
3102 uirow = MSI_CreateRecord(3);
3103 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3104 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3105 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3106 ui_actiondata(package,szProcessComponents,uirow);
3107 msiobj_release( &uirow->hdr );
3108 }
James Hawkins4aa3a992008-06-18 00:49:42 -05003109
3110 return ERROR_SUCCESS;
Aric Stewartb942e182004-07-06 18:50:02 +00003111}
3112
Aric Stewart6e821732005-03-30 10:19:08 +00003113typedef struct {
3114 CLSID clsid;
3115 LPWSTR source;
3116
3117 LPWSTR path;
3118 ITypeLib *ptLib;
3119} typelib_struct;
3120
Mike McCormackf9acfe62005-06-07 20:29:51 +00003121static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
Aric Stewart6e821732005-03-30 10:19:08 +00003122 LPWSTR lpszName, LONG_PTR lParam)
3123{
3124 TLIBATTR *attr;
3125 typelib_struct *tl_struct = (typelib_struct*) lParam;
3126 static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3127 int sz;
3128 HRESULT res;
3129
3130 if (!IS_INTRESOURCE(lpszName))
3131 {
3132 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3133 return TRUE;
3134 }
3135
3136 sz = strlenW(tl_struct->source)+4;
3137 sz *= sizeof(WCHAR);
3138
Mike McCormack2acf8002006-05-25 11:41:39 +09003139 if ((INT_PTR)lpszName == 1)
Aric Stewartca8c4e42005-06-02 15:13:57 +00003140 tl_struct->path = strdupW(tl_struct->source);
3141 else
3142 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003143 tl_struct->path = msi_alloc(sz);
Aric Stewartca8c4e42005-06-02 15:13:57 +00003144 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3145 }
Aric Stewart6e821732005-03-30 10:19:08 +00003146
3147 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3148 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
Michael Stefaniuc704ebf22008-10-08 01:33:34 +02003149 if (FAILED(res))
Aric Stewart6e821732005-03-30 10:19:08 +00003150 {
Mike McCormackee034ba2005-09-20 11:59:14 +00003151 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003152 tl_struct->path = NULL;
3153
3154 return TRUE;
3155 }
3156
3157 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3158 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3159 {
3160 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3161 return FALSE;
3162 }
3163
Mike McCormackee034ba2005-09-20 11:59:14 +00003164 msi_free(tl_struct->path);
Aric Stewart6e821732005-03-30 10:19:08 +00003165 tl_struct->path = NULL;
3166
3167 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3168 ITypeLib_Release(tl_struct->ptLib);
3169
3170 return TRUE;
3171}
3172
Aric Stewart234dc4b2005-06-22 18:27:34 +00003173static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3174{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003175 MSIPACKAGE* package = param;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003176 LPCWSTR component;
Mike McCormack38d67a42005-08-22 09:15:23 +00003177 MSICOMPONENT *comp;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003178 MSIFILE *file;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003179 typelib_struct tl_struct;
James Hawkins469e4a52008-07-28 22:19:47 -05003180 ITypeLib *tlib;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003181 HMODULE module;
James Hawkins469e4a52008-07-28 22:19:47 -05003182 HRESULT hr;
3183
Aric Stewart234dc4b2005-06-22 18:27:34 +00003184 component = MSI_RecordGetString(row,3);
Mike McCormack38d67a42005-08-22 09:15:23 +00003185 comp = get_loaded_component(package,component);
3186 if (!comp)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003187 return ERROR_SUCCESS;
3188
Hans Leidekker598c5422010-02-16 11:44:47 +01003189 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003190 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003191 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003192 comp->Action = comp->Installed;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003193 return ERROR_SUCCESS;
3194 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003195 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart234dc4b2005-06-22 18:27:34 +00003196
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003197 file = get_loaded_file( package, comp->KeyPath );
3198 if (!file)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003199 return ERROR_SUCCESS;
3200
Hans Leidekker54391a12010-02-16 11:44:34 +01003201 ui_actiondata( package, szRegisterTypeLibraries, row );
3202
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003203 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
Mike McCormack51c66182005-10-27 12:36:12 +00003204 if (module)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003205 {
Mike McCormack51c66182005-10-27 12:36:12 +00003206 LPCWSTR guid;
3207 guid = MSI_RecordGetString(row,1);
Mikhail Maroukhinef930c872010-03-26 23:59:50 +06003208 CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00003209 tl_struct.source = strdupW( file->TargetPath );
Aric Stewart234dc4b2005-06-22 18:27:34 +00003210 tl_struct.path = NULL;
3211
3212 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3213 (LONG_PTR)&tl_struct);
3214
Mike McCormack51c66182005-10-27 12:36:12 +00003215 if (tl_struct.path)
Aric Stewart234dc4b2005-06-22 18:27:34 +00003216 {
3217 LPWSTR help = NULL;
3218 LPCWSTR helpid;
3219 HRESULT res;
3220
3221 helpid = MSI_RecordGetString(row,6);
3222
3223 if (helpid)
James Hawkins8cedb212007-03-29 02:38:57 -05003224 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003225 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
Mike McCormackee034ba2005-09-20 11:59:14 +00003226 msi_free(help);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003227
Michael Stefaniuc704ebf22008-10-08 01:33:34 +02003228 if (FAILED(res))
Aric Stewart234dc4b2005-06-22 18:27:34 +00003229 ERR("Failed to register type library %s\n",
3230 debugstr_w(tl_struct.path));
3231 else
Aric Stewart234dc4b2005-06-22 18:27:34 +00003232 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
Aric Stewart234dc4b2005-06-22 18:27:34 +00003233
3234 ITypeLib_Release(tl_struct.ptLib);
Mike McCormackee034ba2005-09-20 11:59:14 +00003235 msi_free(tl_struct.path);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003236 }
3237 else
3238 ERR("Failed to load type library %s\n",
3239 debugstr_w(tl_struct.source));
3240
3241 FreeLibrary(module);
Mike McCormackee034ba2005-09-20 11:59:14 +00003242 msi_free(tl_struct.source);
Aric Stewart234dc4b2005-06-22 18:27:34 +00003243 }
3244 else
James Hawkins469e4a52008-07-28 22:19:47 -05003245 {
3246 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3247 if (FAILED(hr))
3248 {
3249 ERR("Failed to load type library: %08x\n", hr);
Hans Leidekker82d50fa2010-02-12 10:33:00 +01003250 return ERROR_INSTALL_FAILURE;
James Hawkins469e4a52008-07-28 22:19:47 -05003251 }
3252
3253 ITypeLib_Release(tlib);
3254 }
Aric Stewart234dc4b2005-06-22 18:27:34 +00003255
3256 return ERROR_SUCCESS;
3257}
3258
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003259static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
Aric Stewartfcb20c52004-07-06 18:51:16 +00003260{
3261 /*
Mike McCormackc90c7812004-07-09 22:58:27 +00003262 * OK this is a bit confusing.. I am given a _Component key and I believe
Aric Stewartfcb20c52004-07-06 18:51:16 +00003263 * that the file that is being registered as a type library is the "key file
Mike McCormackc90c7812004-07-09 22:58:27 +00003264 * of that component" which I interpret to mean "The file in the KeyPath of
3265 * that component".
Aric Stewartfcb20c52004-07-06 18:51:16 +00003266 */
3267 UINT rc;
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003268 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00003269 static const WCHAR Query[] =
3270 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00003271 '`','T','y','p','e','L','i','b','`',0};
Aric Stewartfcb20c52004-07-06 18:51:16 +00003272
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003273 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003274 if (rc != ERROR_SUCCESS)
Aric Stewart84837d92004-07-20 01:22:37 +00003275 return ERROR_SUCCESS;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003276
Aric Stewart234dc4b2005-06-22 18:27:34 +00003277 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003278 msiobj_release(&view->hdr);
Aric Stewartfcb20c52004-07-06 18:51:16 +00003279 return rc;
Aric Stewartfcb20c52004-07-06 18:51:16 +00003280}
3281
Hans Leidekker98761032010-02-12 10:32:35 +01003282static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3283{
3284 MSIPACKAGE *package = param;
3285 LPCWSTR component, guid;
3286 MSICOMPONENT *comp;
3287 GUID libid;
3288 UINT version;
3289 LCID language;
3290 SYSKIND syskind;
3291 HRESULT hr;
3292
3293 component = MSI_RecordGetString( row, 3 );
3294 comp = get_loaded_component( package, component );
3295 if (!comp)
3296 return ERROR_SUCCESS;
3297
Hans Leidekker598c5422010-02-16 11:44:47 +01003298 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
Hans Leidekker98761032010-02-12 10:32:35 +01003299 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003300 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
Hans Leidekker98761032010-02-12 10:32:35 +01003301 comp->Action = comp->Installed;
3302 return ERROR_SUCCESS;
3303 }
3304 comp->Action = INSTALLSTATE_ABSENT;
3305
Hans Leidekker54391a12010-02-16 11:44:34 +01003306 ui_actiondata( package, szUnregisterTypeLibraries, row );
3307
Hans Leidekker98761032010-02-12 10:32:35 +01003308 guid = MSI_RecordGetString( row, 1 );
Mikhail Maroukhinef930c872010-03-26 23:59:50 +06003309 CLSIDFromString( (LPCWSTR)guid, &libid );
Hans Leidekker98761032010-02-12 10:32:35 +01003310 version = MSI_RecordGetInteger( row, 4 );
3311 language = MSI_RecordGetInteger( row, 2 );
3312
3313#ifdef _WIN64
3314 syskind = SYS_WIN64;
3315#else
3316 syskind = SYS_WIN32;
3317#endif
3318
3319 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3320 if (FAILED(hr))
3321 {
3322 WARN("Failed to unregister typelib: %08x\n", hr);
3323 }
3324
3325 return ERROR_SUCCESS;
3326}
3327
3328static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3329{
3330 UINT rc;
3331 MSIQUERY *view;
3332 static const WCHAR query[] =
3333 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3334 '`','T','y','p','e','L','i','b','`',0};
3335
3336 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3337 if (rc != ERROR_SUCCESS)
3338 return ERROR_SUCCESS;
3339
3340 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3341 msiobj_release( &view->hdr );
3342 return rc;
3343}
3344
Hans Leidekker2276c292010-02-15 10:20:01 +01003345static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3346{
3347 static const WCHAR szlnk[] = {'.','l','n','k',0};
3348 LPCWSTR directory, extension;
3349 LPWSTR link_folder, link_file, filename;
3350
3351 directory = MSI_RecordGetString( row, 2 );
3352 link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3353
3354 /* may be needed because of a bug somewhere else */
3355 create_full_pathW( link_folder );
3356
3357 filename = msi_dup_record_field( row, 3 );
3358 reduce_to_longfilename( filename );
3359
3360 extension = strchrW( filename, '.' );
3361 if (!extension || strcmpiW( extension, szlnk ))
3362 {
3363 int len = strlenW( filename );
3364 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3365 memcpy( filename + len, szlnk, sizeof(szlnk) );
3366 }
3367 link_file = build_directory_name( 2, link_folder, filename );
3368 msi_free( link_folder );
3369 msi_free( filename );
3370
3371 return link_file;
3372}
3373
Aric Stewart9adacf62005-06-24 11:58:21 +00003374static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003375{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003376 MSIPACKAGE *package = param;
Hans Leidekker2276c292010-02-15 10:20:01 +01003377 LPWSTR link_file, deformated, path;
3378 LPCWSTR component, target;
Mike McCormack38d67a42005-08-22 09:15:23 +00003379 MSICOMPONENT *comp;
Mike McCormack20c57462006-05-24 17:41:04 +09003380 IShellLinkW *sl = NULL;
3381 IPersistFile *pf = NULL;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003382 HRESULT res;
3383
Hans Leidekker2276c292010-02-15 10:20:01 +01003384 component = MSI_RecordGetString(row, 4);
3385 comp = get_loaded_component(package, component);
Mike McCormack38d67a42005-08-22 09:15:23 +00003386 if (!comp)
Aric Stewart9adacf62005-06-24 11:58:21 +00003387 return ERROR_SUCCESS;
3388
Hans Leidekker598c5422010-02-16 11:44:47 +01003389 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewart9adacf62005-06-24 11:58:21 +00003390 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003391 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00003392 comp->Action = comp->Installed;
Aric Stewart9adacf62005-06-24 11:58:21 +00003393 return ERROR_SUCCESS;
3394 }
Mike McCormack38d67a42005-08-22 09:15:23 +00003395 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewart9adacf62005-06-24 11:58:21 +00003396
3397 ui_actiondata(package,szCreateShortcuts,row);
3398
3399 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3400 &IID_IShellLinkW, (LPVOID *) &sl );
3401
Mike McCormack20c57462006-05-24 17:41:04 +09003402 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003403 {
Mike McCormack20c57462006-05-24 17:41:04 +09003404 ERR("CLSID_ShellLink not available\n");
3405 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003406 }
3407
3408 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
Mike McCormack20c57462006-05-24 17:41:04 +09003409 if (FAILED( res ))
Aric Stewart9adacf62005-06-24 11:58:21 +00003410 {
Mike McCormack20c57462006-05-24 17:41:04 +09003411 ERR("QueryInterface(IID_IPersistFile) failed\n");
3412 goto err;
Aric Stewart9adacf62005-06-24 11:58:21 +00003413 }
3414
Hans Leidekker2276c292010-02-15 10:20:01 +01003415 target = MSI_RecordGetString(row, 5);
3416 if (strchrW(target, '['))
Robert Shearman4ac85672006-02-22 16:31:00 +00003417 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003418 deformat_string(package, target, &deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003419 IShellLinkW_SetPath(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003420 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003421 }
3422 else
3423 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003424 FIXME("poorly handled shortcut format, advertised shortcut\n");
Mike McCormack566c69e2005-09-22 10:49:17 +00003425 IShellLinkW_SetPath(sl,comp->FullKeypath);
Aric Stewart9adacf62005-06-24 11:58:21 +00003426 }
3427
3428 if (!MSI_RecordIsNull(row,6))
3429 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003430 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3431 deformat_string(package, arguments, &deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003432 IShellLinkW_SetArguments(sl,deformated);
Mike McCormackee034ba2005-09-20 11:59:14 +00003433 msi_free(deformated);
Aric Stewart9adacf62005-06-24 11:58:21 +00003434 }
3435
3436 if (!MSI_RecordIsNull(row,7))
3437 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003438 LPCWSTR description = MSI_RecordGetString(row, 7);
3439 IShellLinkW_SetDescription(sl, description);
Aric Stewart9adacf62005-06-24 11:58:21 +00003440 }
3441
3442 if (!MSI_RecordIsNull(row,8))
3443 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3444
3445 if (!MSI_RecordIsNull(row,9))
3446 {
Aric Stewart9adacf62005-06-24 11:58:21 +00003447 INT index;
Hans Leidekker2276c292010-02-15 10:20:01 +01003448 LPCWSTR icon = MSI_RecordGetString(row, 9);
Aric Stewart9adacf62005-06-24 11:58:21 +00003449
Hans Leidekker2276c292010-02-15 10:20:01 +01003450 path = build_icon_path(package, icon);
Aric Stewart9adacf62005-06-24 11:58:21 +00003451 index = MSI_RecordGetInteger(row,10);
3452
Robert Shearmanab378802006-08-03 20:24:10 +01003453 /* no value means 0 */
3454 if (index == MSI_NULL_INTEGER)
3455 index = 0;
3456
Hans Leidekker2276c292010-02-15 10:20:01 +01003457 IShellLinkW_SetIconLocation(sl, path, index);
3458 msi_free(path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003459 }
3460
3461 if (!MSI_RecordIsNull(row,11))
3462 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3463
3464 if (!MSI_RecordIsNull(row,12))
3465 {
Hans Leidekker2276c292010-02-15 10:20:01 +01003466 LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3467 path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3468 if (path)
3469 IShellLinkW_SetWorkingDirectory(sl, path);
3470 msi_free(path);
Aric Stewart9adacf62005-06-24 11:58:21 +00003471 }
3472
Hans Leidekker2276c292010-02-15 10:20:01 +01003473 link_file = get_link_file(package, row);
Aric Stewart9adacf62005-06-24 11:58:21 +00003474
Hans Leidekker2276c292010-02-15 10:20:01 +01003475 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3476 IPersistFile_Save(pf, link_file, FALSE);
3477
3478 msi_free(link_file);
Aric Stewart9adacf62005-06-24 11:58:21 +00003479
Mike McCormack20c57462006-05-24 17:41:04 +09003480err:
3481 if (pf)
3482 IPersistFile_Release( pf );
3483 if (sl)
3484 IShellLinkW_Release( sl );
Aric Stewart9adacf62005-06-24 11:58:21 +00003485
3486 return ERROR_SUCCESS;
3487}
3488
3489static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3490{
3491 UINT rc;
3492 HRESULT res;
3493 MSIQUERY * view;
3494 static const WCHAR Query[] =
3495 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3496 '`','S','h','o','r','t','c','u','t','`',0};
3497
Aric Stewart9adacf62005-06-24 11:58:21 +00003498 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3499 if (rc != ERROR_SUCCESS)
3500 return ERROR_SUCCESS;
3501
Aric Stewart2cf222f2004-07-06 19:00:23 +00003502 res = CoInitialize( NULL );
Aric Stewart2cf222f2004-07-06 19:00:23 +00003503
Aric Stewart9adacf62005-06-24 11:58:21 +00003504 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003505 msiobj_release(&view->hdr);
Aric Stewart2cf222f2004-07-06 19:00:23 +00003506
Hans Leidekkerdd1ca6c2009-09-10 10:10:33 +02003507 if (SUCCEEDED(res))
3508 CoUninitialize();
Aric Stewart2cf222f2004-07-06 19:00:23 +00003509
3510 return rc;
3511}
3512
Hans Leidekker2276c292010-02-15 10:20:01 +01003513static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3514{
3515 MSIPACKAGE *package = param;
3516 LPWSTR link_file;
3517 LPCWSTR component;
3518 MSICOMPONENT *comp;
3519
3520 component = MSI_RecordGetString( row, 4 );
3521 comp = get_loaded_component( package, component );
3522 if (!comp)
3523 return ERROR_SUCCESS;
3524
Hans Leidekker598c5422010-02-16 11:44:47 +01003525 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
Hans Leidekker2276c292010-02-15 10:20:01 +01003526 {
Hans Leidekker598c5422010-02-16 11:44:47 +01003527 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
Hans Leidekker2276c292010-02-15 10:20:01 +01003528 comp->Action = comp->Installed;
3529 return ERROR_SUCCESS;
3530 }
3531 comp->Action = INSTALLSTATE_ABSENT;
3532
3533 ui_actiondata( package, szRemoveShortcuts, row );
3534
3535 link_file = get_link_file( package, row );
3536
3537 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3538 if (!DeleteFileW( link_file ))
3539 {
3540 WARN("Failed to remove shortcut file %u\n", GetLastError());
3541 }
3542 msi_free( link_file );
3543
3544 return ERROR_SUCCESS;
3545}
3546
3547static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3548{
3549 UINT rc;
3550 MSIQUERY *view;
3551 static const WCHAR query[] =
3552 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3553 '`','S','h','o','r','t','c','u','t','`',0};
3554
3555 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3556 if (rc != ERROR_SUCCESS)
3557 return ERROR_SUCCESS;
3558
3559 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3560 msiobj_release( &view->hdr );
3561
3562 return rc;
3563}
3564
James Hawkinsfac97bb2008-06-23 22:56:56 -05003565static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
Aric Stewart916ef942005-06-22 18:42:19 +00003566{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01003567 MSIPACKAGE* package = param;
Aric Stewart916ef942005-06-22 18:42:19 +00003568 HANDLE the_file;
Mike McCormack75658d72005-09-22 10:33:57 +00003569 LPWSTR FilePath;
3570 LPCWSTR FileName;
Aric Stewart916ef942005-06-22 18:42:19 +00003571 CHAR buffer[1024];
3572 DWORD sz;
3573 UINT rc;
3574
3575 FileName = MSI_RecordGetString(row,1);
3576 if (!FileName)
3577 {
3578 ERR("Unable to get FileName\n");
3579 return ERROR_SUCCESS;
3580 }
3581
Mike McCormack75658d72005-09-22 10:33:57 +00003582 FilePath = build_icon_path(package,FileName);
Aric Stewart916ef942005-06-22 18:42:19 +00003583
3584 TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3585
3586 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3587 FILE_ATTRIBUTE_NORMAL, NULL);
3588
3589 if (the_file == INVALID_HANDLE_VALUE)
3590 {
3591 ERR("Unable to create file %s\n",debugstr_w(FilePath));
Mike McCormackee034ba2005-09-20 11:59:14 +00003592 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003593 return ERROR_SUCCESS;
3594 }
3595
3596 do
3597 {
3598 DWORD write;
3599 sz = 1024;
3600 rc = MSI_RecordReadStream(row,2,buffer,&sz);
3601 if (rc != ERROR_SUCCESS)
3602 {
3603 ERR("Failed to get stream\n");
3604 CloseHandle(the_file);
3605 DeleteFileW(FilePath);
3606 break;
3607 }
3608 WriteFile(the_file,buffer,sz,&write,NULL);
3609 } while (sz == 1024);
3610
Mike McCormackee034ba2005-09-20 11:59:14 +00003611 msi_free(FilePath);
Aric Stewart916ef942005-06-22 18:42:19 +00003612 CloseHandle(the_file);
Robert Shearmand2e48e02006-01-23 17:29:50 +01003613
Aric Stewart916ef942005-06-22 18:42:19 +00003614 return ERROR_SUCCESS;
3615}
Aric Stewart2cf222f2004-07-06 19:00:23 +00003616
James Hawkinsfac97bb2008-06-23 22:56:56 -05003617static UINT msi_publish_icons(MSIPACKAGE *package)
3618{
3619 UINT r;
3620 MSIQUERY *view;
3621
3622 static const WCHAR query[]= {
3623 'S','E','L','E','C','T',' ','*',' ',
3624 'F','R','O','M',' ','`','I','c','o','n','`',0};
3625
3626 r = MSI_DatabaseOpenViewW(package->db, query, &view);
3627 if (r == ERROR_SUCCESS)
3628 {
3629 MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3630 msiobj_release(&view->hdr);
3631 }
3632
3633 return ERROR_SUCCESS;
3634}
3635
James Hawkins2d4e4b62008-06-23 23:05:25 -05003636static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
James Hawkins68e60712008-06-23 22:57:36 -05003637{
3638 UINT r;
James Hawkins2d4e4b62008-06-23 23:05:25 -05003639 HKEY source;
James Hawkins68e60712008-06-23 22:57:36 -05003640 LPWSTR buffer;
3641 MSIMEDIADISK *disk;
3642 MSISOURCELISTINFO *info;
3643
James Hawkins2d4e4b62008-06-23 23:05:25 -05003644 r = RegCreateKeyW(hkey, szSourceList, &source);
3645 if (r != ERROR_SUCCESS)
3646 return r;
3647
3648 RegCloseKey(source);
James Hawkins68e60712008-06-23 22:57:36 -05003649
3650 buffer = strrchrW(package->PackagePath, '\\') + 1;
3651 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3652 package->Context, MSICODE_PRODUCT,
3653 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3654 if (r != ERROR_SUCCESS)
3655 return r;
3656
3657 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3658 package->Context, MSICODE_PRODUCT,
3659 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3660 if (r != ERROR_SUCCESS)
3661 return r;
3662
3663 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3664 package->Context, MSICODE_PRODUCT,
3665 INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3666 if (r != ERROR_SUCCESS)
3667 return r;
3668
3669 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3670 {
3671 if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3672 msi_set_last_used_source(package->ProductCode, NULL, info->context,
3673 info->options, info->value);
3674 else
3675 MsiSourceListSetInfoW(package->ProductCode, NULL,
3676 info->context, info->options,
3677 info->property, info->value);
3678 }
3679
3680 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3681 {
3682 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3683 disk->context, disk->options,
3684 disk->disk_id, disk->volume_label, disk->disk_prompt);
3685 }
3686
3687 return ERROR_SUCCESS;
3688}
3689
James Hawkinsebeb5372008-06-23 22:59:41 -05003690static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3691{
3692 MSIHANDLE hdb, suminfo;
3693 WCHAR guids[MAX_PATH];
James Hawkinsdb2e8d22008-06-23 23:00:21 -05003694 WCHAR packcode[SQUISH_GUID_SIZE];
James Hawkinsebeb5372008-06-23 22:59:41 -05003695 LPWSTR buffer;
3696 LPWSTR ptr;
3697 DWORD langid;
3698 DWORD size;
3699 UINT r;
3700
3701 static const WCHAR szProductLanguage[] =
3702 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3703 static const WCHAR szARPProductIcon[] =
3704 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3705 static const WCHAR szProductVersion[] =
3706 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
James Hawkinsef640a62008-06-23 23:01:44 -05003707 static const WCHAR szAssignment[] =
3708 {'A','s','s','i','g','n','m','e','n','t',0};
3709 static const WCHAR szAdvertiseFlags[] =
3710 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3711 static const WCHAR szClients[] =
3712 {'C','l','i','e','n','t','s',0};
3713 static const WCHAR szColon[] = {':',0};
James Hawkinsebeb5372008-06-23 22:59:41 -05003714
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003715 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
James Hawkinsebeb5372008-06-23 22:59:41 -05003716 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3717 msi_free(buffer);
3718
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003719 langid = msi_get_property_int(package->db, szProductLanguage, 0);
James Hawkinsebeb5372008-06-23 22:59:41 -05003720 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3721
James Hawkinsebeb5372008-06-23 22:59:41 -05003722 /* FIXME */
3723 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3724
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003725 buffer = msi_dup_property(package->db, szARPProductIcon);
James Hawkinsebeb5372008-06-23 22:59:41 -05003726 if (buffer)
3727 {
3728 LPWSTR path = build_icon_path(package,buffer);
3729 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3730 msi_free(path);
3731 msi_free(buffer);
3732 }
3733
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003734 buffer = msi_dup_property(package->db, szProductVersion);
James Hawkinsebeb5372008-06-23 22:59:41 -05003735 if (buffer)
3736 {
3737 DWORD verdword = msi_version_str_to_dword(buffer);
3738 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3739 msi_free(buffer);
3740 }
3741
James Hawkinsef640a62008-06-23 23:01:44 -05003742 msi_reg_set_val_dword(hkey, szAssignment, 0);
3743 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3744 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3745 msi_reg_set_val_str(hkey, szClients, szColon);
3746
James Hawkinsebeb5372008-06-23 22:59:41 -05003747 hdb = alloc_msihandle(&package->db->hdr);
3748 if (!hdb)
3749 return ERROR_NOT_ENOUGH_MEMORY;
3750
3751 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3752 MsiCloseHandle(hdb);
3753 if (r != ERROR_SUCCESS)
3754 goto done;
3755
3756 size = MAX_PATH;
3757 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3758 NULL, guids, &size);
3759 if (r != ERROR_SUCCESS)
3760 goto done;
3761
3762 ptr = strchrW(guids, ';');
3763 if (ptr) *ptr = 0;
James Hawkinsdb2e8d22008-06-23 23:00:21 -05003764 squash_guid(guids, packcode);
3765 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
James Hawkinsebeb5372008-06-23 22:59:41 -05003766
3767done:
3768 MsiCloseHandle(suminfo);
3769 return ERROR_SUCCESS;
3770}
3771
James Hawkinscdb33f82008-06-23 23:02:54 -05003772static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3773{
3774 UINT r;
3775 HKEY hkey;
3776 LPWSTR upgrade;
3777 WCHAR squashed_pc[SQUISH_GUID_SIZE];
3778
3779 static const WCHAR szUpgradeCode[] =
3780 {'U','p','g','r','a','d','e','C','o','d','e',0};
3781
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003782 upgrade = msi_dup_property(package->db, szUpgradeCode);
James Hawkinscdb33f82008-06-23 23:02:54 -05003783 if (!upgrade)
3784 return ERROR_SUCCESS;
3785
James Hawkins58e15432008-06-23 23:04:46 -05003786 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3787 {
3788 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3789 if (r != ERROR_SUCCESS)
3790 goto done;
3791 }
3792 else
3793 {
3794 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3795 if (r != ERROR_SUCCESS)
3796 goto done;
3797 }
James Hawkinscdb33f82008-06-23 23:02:54 -05003798
3799 squash_guid(package->ProductCode, squashed_pc);
3800 msi_reg_set_val_str(hkey, squashed_pc, NULL);
3801
3802 RegCloseKey(hkey);
3803
3804done:
3805 msi_free(upgrade);
3806 return r;
3807}
3808
James Hawkinsa2df31a2007-07-02 20:21:26 -07003809static BOOL msi_check_publish(MSIPACKAGE *package)
3810{
3811 MSIFEATURE *feature;
3812
3813 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3814 {
3815 if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3816 return TRUE;
3817 }
3818
3819 return FALSE;
3820}
3821
James Hawkinscdb33f82008-06-23 23:02:54 -05003822static BOOL msi_check_unpublish(MSIPACKAGE *package)
3823{
3824 MSIFEATURE *feature;
3825
3826 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3827 {
3828 if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3829 return FALSE;
3830 }
3831
3832 return TRUE;
3833}
3834
Hans Leidekker920fc342010-05-04 09:07:39 +02003835static UINT msi_publish_patches( MSIPACKAGE *package, HKEY prodkey )
James Hawkins01eb9302008-12-14 21:07:23 -06003836{
Hans Leidekker920fc342010-05-04 09:07:39 +02003837 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
James Hawkins01eb9302008-12-14 21:07:23 -06003838 WCHAR patch_squashed[GUID_SIZE];
Hans Leidekker920fc342010-05-04 09:07:39 +02003839 HKEY patches_key = NULL, product_patches_key;
James Hawkins01eb9302008-12-14 21:07:23 -06003840 LONG res;
Hans Leidekker162780d2010-04-29 09:39:22 +02003841 MSIPATCHINFO *patch;
Hans Leidekker920fc342010-05-04 09:07:39 +02003842 UINT r;
Hans Leidekker162780d2010-04-29 09:39:22 +02003843 WCHAR *p, *all_patches = NULL;
3844 DWORD len = 0;
James Hawkins01eb9302008-12-14 21:07:23 -06003845
Hans Leidekker920fc342010-05-04 09:07:39 +02003846 res = RegCreateKeyExW( prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
James Hawkins01eb9302008-12-14 21:07:23 -06003847 if (res != ERROR_SUCCESS)
3848 return ERROR_FUNCTION_FAILED;
3849
Hans Leidekker920fc342010-05-04 09:07:39 +02003850 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
3851 if (r != ERROR_SUCCESS)
3852 goto done;
3853
Hans Leidekker162780d2010-04-29 09:39:22 +02003854 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3855 {
3856 squash_guid( patch->patchcode, patch_squashed );
3857 len += strlenW( patch_squashed ) + 1;
3858 }
James Hawkins01eb9302008-12-14 21:07:23 -06003859
Hans Leidekker162780d2010-04-29 09:39:22 +02003860 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
3861 if (!all_patches)
James Hawkins01eb9302008-12-14 21:07:23 -06003862 goto done;
3863
Hans Leidekker162780d2010-04-29 09:39:22 +02003864 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
3865 {
Hans Leidekker920fc342010-05-04 09:07:39 +02003866 HKEY patch_key;
3867
Hans Leidekker162780d2010-04-29 09:39:22 +02003868 squash_guid( patch->patchcode, p );
3869 p += strlenW( p ) + 1;
3870
Hans Leidekker920fc342010-05-04 09:07:39 +02003871 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
Hans Leidekker162780d2010-04-29 09:39:22 +02003872 (const BYTE *)patch->transforms,
3873 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
3874 if (res != ERROR_SUCCESS)
3875 goto done;
Hans Leidekker920fc342010-05-04 09:07:39 +02003876
3877 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
3878 if (r != ERROR_SUCCESS)
3879 goto done;
3880
3881 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
3882 (const BYTE *)patch->localfile,
3883 (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
3884 RegCloseKey( patch_key );
3885 if (res != ERROR_SUCCESS)
3886 goto done;
3887
3888 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
3889 RegCloseKey( patch_key );
3890 if (res != ERROR_SUCCESS)
3891 goto done;
Hans Leidekker162780d2010-04-29 09:39:22 +02003892 }
3893
3894 all_patches[len] = 0;
Hans Leidekker920fc342010-05-04 09:07:39 +02003895 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
Hans Leidekker162780d2010-04-29 09:39:22 +02003896 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
Hans Leidekker920fc342010-05-04 09:07:39 +02003897 if (res != ERROR_SUCCESS)
3898 goto done;
3899
3900 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
3901 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
3902 if (res != ERROR_SUCCESS)
3903 r = ERROR_FUNCTION_FAILED;
James Hawkins01eb9302008-12-14 21:07:23 -06003904
3905done:
Hans Leidekker920fc342010-05-04 09:07:39 +02003906 RegCloseKey( product_patches_key );
3907 RegCloseKey( patches_key );
Hans Leidekker162780d2010-04-29 09:39:22 +02003908 msi_free( all_patches );
James Hawkins01eb9302008-12-14 21:07:23 -06003909 return r;
3910}
3911
Aric Stewart2cf222f2004-07-06 19:00:23 +00003912/*
3913 * 99% of the work done here is only done for
3914 * advertised installs. However this is where the
3915 * Icon table is processed and written out
Francois Gouget817c5202004-07-16 19:15:40 +00003916 * so that is what I am going to do here.
Aric Stewart2cf222f2004-07-06 19:00:23 +00003917 */
Alexandre Julliarda7a6f5f2004-07-09 22:25:34 +00003918static UINT ACTION_PublishProduct(MSIPACKAGE *package)
Aric Stewart2cf222f2004-07-06 19:00:23 +00003919{
3920 UINT rc;
Hans Leidekkerc547fb32010-03-05 12:27:49 +01003921 HKEY hukey = NULL, hudkey = NULL;
3922 MSIRECORD *uirow;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003923
James Hawkinsa2df31a2007-07-02 20:21:26 -07003924 /* FIXME: also need to publish if the product is in advertise mode */
3925 if (!msi_check_publish(package))
3926 return ERROR_SUCCESS;
3927
James Hawkinsc965d832009-03-22 14:30:16 -07003928 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
James Hawkins70be1e72008-11-03 22:16:43 -06003929 &hukey, TRUE);
3930 if (rc != ERROR_SUCCESS)
3931 goto end;
3932
James Hawkins4a9f6992008-12-14 21:07:06 -06003933 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3934 NULL, &hudkey, TRUE);
3935 if (rc != ERROR_SUCCESS)
3936 goto end;
Aric Stewart6269f002005-01-17 13:40:39 +00003937
James Hawkinscdb33f82008-06-23 23:02:54 -05003938 rc = msi_publish_upgrade_code(package);
3939 if (rc != ERROR_SUCCESS)
3940 goto end;
James Hawkinsebeb5372008-06-23 22:59:41 -05003941
Hans Leidekker162780d2010-04-29 09:39:22 +02003942 if (!list_empty(&package->patches))
James Hawkins01eb9302008-12-14 21:07:23 -06003943 {
Hans Leidekker920fc342010-05-04 09:07:39 +02003944 rc = msi_publish_patches(package, hukey);
James Hawkins01eb9302008-12-14 21:07:23 -06003945 if (rc != ERROR_SUCCESS)
3946 goto end;
3947 }
3948
James Hawkinsebeb5372008-06-23 22:59:41 -05003949 rc = msi_publish_product_properties(package, hukey);
3950 if (rc != ERROR_SUCCESS)
Dan Kegel337e1e22006-08-28 09:44:35 -07003951 goto end;
Aric Stewart2cae30b2005-01-19 19:07:40 +00003952
James Hawkins2d4e4b62008-06-23 23:05:25 -05003953 rc = msi_publish_sourcelist(package, hukey);
James Hawkins68e60712008-06-23 22:57:36 -05003954 if (rc != ERROR_SUCCESS)
3955 goto end;
James Hawkins5e46fc92007-07-02 20:20:20 -07003956
James Hawkins68e60712008-06-23 22:57:36 -05003957 rc = msi_publish_icons(package);
James Hawkinsfac97bb2008-06-23 22:56:56 -05003958
Aric Stewart6269f002005-01-17 13:40:39 +00003959end:
Hans Leidekkerc547fb32010-03-05 12:27:49 +01003960 uirow = MSI_CreateRecord( 1 );
3961 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
3962 ui_actiondata( package, szPublishProduct, uirow );
3963 msiobj_release( &uirow->hdr );
3964
Aric Stewart6269f002005-01-17 13:40:39 +00003965 RegCloseKey(hukey);
James Hawkinsc18b7752007-06-26 19:22:46 -07003966 RegCloseKey(hudkey);
Aric Stewart6269f002005-01-17 13:40:39 +00003967
Aric Stewart2cf222f2004-07-06 19:00:23 +00003968 return rc;
Aric Stewart2cf222f2004-07-06 19:00:23 +00003969}
3970
Hans Leidekkerb891d082010-03-02 14:58:55 +01003971static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
3972{
3973 WCHAR *filename, *ptr, *folder, *ret;
3974 const WCHAR *dirprop;
3975
3976 filename = msi_dup_record_field( row, 2 );
3977 if (filename && (ptr = strchrW( filename, '|' )))
3978 ptr++;
3979 else
3980 ptr = filename;
3981
3982 dirprop = MSI_RecordGetString( row, 3 );
3983 if (dirprop)
3984 {
3985 folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
3986 if (!folder)
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003987 folder = msi_dup_property( package->db, dirprop );
Hans Leidekkerb891d082010-03-02 14:58:55 +01003988 }
3989 else
Hans Leidekker186f4ef2010-04-21 11:37:54 +02003990 folder = msi_dup_property( package->db, szWindowsFolder );
Hans Leidekkerb891d082010-03-02 14:58:55 +01003991
3992 if (!folder)
3993 {
3994 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
3995 msi_free( filename );
3996 return NULL;
3997 }
3998
3999 ret = build_directory_name( 2, folder, ptr );
4000
4001 msi_free( filename );
4002 msi_free( folder );
4003 return ret;
4004}
4005
Aric Stewartaded32f2005-06-23 09:46:31 +00004006static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4007{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01004008 MSIPACKAGE *package = param;
Hans Leidekkerb891d082010-03-02 14:58:55 +01004009 LPCWSTR component, section, key, value, identifier;
4010 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
Aric Stewartaded32f2005-06-23 09:46:31 +00004011 MSIRECORD * uirow;
Mike McCormack38d67a42005-08-22 09:15:23 +00004012 INT action;
4013 MSICOMPONENT *comp;
Aric Stewartaded32f2005-06-23 09:46:31 +00004014
4015 component = MSI_RecordGetString(row, 8);
Mike McCormack38d67a42005-08-22 09:15:23 +00004016 comp = get_loaded_component(package,component);
Hans Leidekker598c5422010-02-16 11:44:47 +01004017 if (!comp)
4018 return ERROR_SUCCESS;
Aric Stewartaded32f2005-06-23 09:46:31 +00004019
Hans Leidekker598c5422010-02-16 11:44:47 +01004020 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
Aric Stewartaded32f2005-06-23 09:46:31 +00004021 {
Hans Leidekker598c5422010-02-16 11:44:47 +01004022 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
Mike McCormack38d67a42005-08-22 09:15:23 +00004023 comp->Action = comp->Installed;
Aric Stewartaded32f2005-06-23 09:46:31 +00004024 return ERROR_SUCCESS;
4025 }
Mike McCormack38d67a42005-08-22 09:15:23 +00004026 comp->Action = INSTALLSTATE_LOCAL;
Aric Stewartaded32f2005-06-23 09:46:31 +00004027
4028 identifier = MSI_RecordGetString(row,1);
Aric Stewartaded32f2005-06-23 09:46:31 +00004029 section = MSI_RecordGetString(row,4);
4030 key = MSI_RecordGetString(row,5);
4031 value = MSI_RecordGetString(row,6);
4032 action = MSI_RecordGetInteger(row,7);
4033
4034 deformat_string(package,section,&deformated_section);
4035 deformat_string(package,key,&deformated_key);
4036 deformat_string(package,value,&deformated_value);
4037
Hans Leidekkerb891d082010-03-02 14:58:55 +01004038 fullname = get_ini_file_name(package, row);
Aric Stewartaded32f2005-06-23 09:46:31 +00004039
4040 if (action == 0)
4041 {
4042 TRACE("Adding value %s to section %s in %s\n",
4043 debugstr_w(deformated_key), debugstr_w(deformated_section),
4044 debugstr_w(fullname));
4045 WritePrivateProfileStringW(deformated_section, deformated_key,
4046 deformated_value, fullname);
4047 }
4048 else if (action == 1)
4049 {
4050 WCHAR returned[10];
4051 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4052 returned, 10, fullname);
4053 if (returned[0] == 0)
4054 {
4055 TRACE("Adding value %s to section %s in %s\n",
4056 debugstr_w(deformated_key), debugstr_w(deformated_section),
4057 debugstr_w(fullname));
4058
4059 WritePrivateProfileStringW(deformated_section, deformated_key,
4060 deformated_value, fullname);
4061 }
4062 }
4063 else if (action == 3)
4064 FIXME("Append to existing section not yet implemented\n");
4065
4066 uirow = MSI_CreateRecord(4);
4067 MSI_RecordSetStringW(uirow,1,identifier);
4068 MSI_RecordSetStringW(uirow,2,deformated_section);
4069 MSI_RecordSetStringW(uirow,3,deformated_key);
4070 MSI_RecordSetStringW(uirow,4,deformated_value);
4071 ui_actiondata(package,szWriteIniValues,uirow);
4072 msiobj_release( &uirow->hdr );
James Hawkinsbf9538f2008-10-27 00:56:04 -05004073
Mike McCormackee034ba2005-09-20 11:59:14 +00004074 msi_free(fullname);
Mike McCormackee034ba2005-09-20 11:59:14 +00004075 msi_free(deformated_key);
4076 msi_free(deformated_value);
4077 msi_free(deformated_section);
Aric Stewartaded32f2005-06-23 09:46:31 +00004078 return ERROR_SUCCESS;
4079}
4080
Aric Stewart516a9c72005-01-14 15:59:26 +00004081static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4082{
4083 UINT rc;
4084 MSIQUERY * view;
Aric Stewart8e233e92005-03-01 11:45:19 +00004085 static const WCHAR ExecSeqQuery[] =
4086 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00004087 '`','I','n','i','F','i','l','e','`',0};
Aric Stewart516a9c72005-01-14 15:59:26 +00004088
4089 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4090 if (rc != ERROR_SUCCESS)
4091 {
4092 TRACE("no IniFile table\n");
4093 return ERROR_SUCCESS;
4094 }
4095
Aric Stewartaded32f2005-06-23 09:46:31 +00004096 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
Aric Stewart516a9c72005-01-14 15:59:26 +00004097 msiobj_release(&view->hdr);
4098 return rc;
4099}
4100
Hans Leidekkerb891d082010-03-02 14:58:55 +01004101static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4102{
4103 MSIPACKAGE *package = param;
4104 LPCWSTR component, section, key, value, identifier;
4105 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4106 MSICOMPONENT *comp;
4107 MSIRECORD *uirow;
4108 INT action;
4109
4110 component = MSI_RecordGetString( row, 8 );
4111 comp = get_loaded_component( package, component );
4112 if (!comp)
4113 return ERROR_SUCCESS;
4114
4115 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4116 {
4117 TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4118 comp->Action = comp->Installed;
4119 return ERROR_SUCCESS;
4120 }
4121 comp->Action = INSTALLSTATE_ABSENT;
4122
4123 identifier = MSI_RecordGetString( row, 1 );
4124 section = MSI_RecordGetString( row, 4 );
4125 key = MSI_RecordGetString( row, 5 );
4126 value = MSI_RecordGetString( row, 6 );
4127 action = MSI_RecordGetInteger( row, 7 );
4128
4129 deformat_string( package, section, &deformated_section );
4130 deformat_string( package, key, &deformated_key );
4131 deformat_string( package, value, &deformated_value );
4132
4133 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4134 {
4135 filename = get_ini_file_name( package, row );
4136
4137 TRACE("Removing key %s from section %s in %s\n",
4138 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4139
4140 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4141 {
4142 WARN("Unable to remove key %u\n", GetLastError());
4143 }
4144 msi_free( filename );
4145 }
4146 else
4147 FIXME("Unsupported action %d\n", action);
4148
4149
4150 uirow = MSI_CreateRecord( 4 );
4151 MSI_RecordSetStringW( uirow, 1, identifier );
4152 MSI_RecordSetStringW( uirow, 2, deformated_section );
4153 MSI_RecordSetStringW( uirow, 3, deformated_key );
4154 MSI_RecordSetStringW( uirow, 4, deformated_value );
4155 ui_actiondata( package, szRemoveIniValues, uirow );
4156 msiobj_release( &uirow->hdr );
4157
4158 msi_free( deformated_key );
4159 msi_free( deformated_value );
4160 msi_free( deformated_section );
4161 return ERROR_SUCCESS;
4162}
4163
4164static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4165{
4166 MSIPACKAGE *package = param;
4167 LPCWSTR component, section, key, value, identifier;
4168 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4169 MSICOMPONENT *comp;
4170 MSIRECORD *uirow;
4171 INT action;
4172
4173 component = MSI_RecordGetString( row, 8 );
4174 comp = get_loaded_component( package, component );
4175 if (!comp)
4176 return ERROR_SUCCESS;
4177
4178 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4179 {
4180 TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4181 comp->Action = comp->Installed;
4182 return ERROR_SUCCESS;
4183 }
4184 comp->Action = INSTALLSTATE_LOCAL;
4185
4186 identifier = MSI_RecordGetString( row, 1 );
4187 section = MSI_RecordGetString( row, 4 );
4188 key = MSI_RecordGetString( row, 5 );
4189 value = MSI_RecordGetString( row, 6 );
4190 action = MSI_RecordGetInteger( row, 7 );
4191
4192 deformat_string( package, section, &deformated_section );
4193 deformat_string( package, key, &deformated_key );
4194 deformat_string( package, value, &deformated_value );
4195
4196 if (action == msidbIniFileActionRemoveLine)
4197 {
4198 filename = get_ini_file_name( package, row );
4199
4200 TRACE("Removing key %s from section %s in %s\n",
4201 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4202
4203 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4204 {
4205 WARN("Unable to remove key %u\n", GetLastError());
4206 }
4207 msi_free( filename );
4208 }
4209 else
4210 FIXME("Unsupported action %d\n", action);
4211
4212 uirow = MSI_CreateRecord( 4 );
4213 MSI_RecordSetStringW( uirow, 1, identifier );
4214 MSI_RecordSetStringW( uirow, 2, deformated_section );
4215 MSI_RecordSetStringW( uirow, 3, deformated_key );
4216 MSI_RecordSetStringW( uirow, 4, deformated_value );
4217 ui_actiondata( package, szRemoveIniValues, uirow );
4218 msiobj_release( &uirow->hdr );
4219
4220 msi_free( deformated_key );
4221 msi_free( deformated_value );
4222 msi_free( deformated_section );
4223 return ERROR_SUCCESS;
4224}
4225
4226static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4227{
4228 UINT rc;
4229 MSIQUERY *view;
4230 static const WCHAR query[] =
4231 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4232 '`','I','n','i','F','i','l','e','`',0};
4233 static const WCHAR remove_query[] =
4234 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4235 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4236
4237 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4238 if (rc == ERROR_SUCCESS)
4239 {
4240 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4241 msiobj_release( &view->hdr );
4242 if (rc != ERROR_SUCCESS)
4243 return rc;
4244 }
4245
4246 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4247 if (rc == ERROR_SUCCESS)
4248 {
4249 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4250 msiobj_release( &view->hdr );
4251 if (rc != ERROR_SUCCESS)
4252 return rc;
4253 }
4254
4255 return ERROR_SUCCESS;
4256}
4257
Aric Stewart854bfc42005-06-24 11:33:02 +00004258static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
Aric Stewart6269f002005-01-17 13:40:39 +00004259{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01004260 MSIPACKAGE *package = param;
Aric Stewart854bfc42005-06-24 11:33:02 +00004261 LPCWSTR filename;
4262 LPWSTR FullName;
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004263 MSIFILE *file;
Aric Stewart854bfc42005-06-24 11:33:02 +00004264 DWORD len;
Aric Stewart8e233e92005-03-01 11:45:19 +00004265 static const WCHAR ExeStr[] =
Aric Stewartc5a14432005-05-18 17:46:12 +00004266 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
4267 static const WCHAR close[] = {'\"',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004268 STARTUPINFOW si;
4269 PROCESS_INFORMATION info;
4270 BOOL brc;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004271 MSIRECORD *uirow;
4272 LPWSTR uipath, p;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004273
4274 memset(&si,0,sizeof(STARTUPINFOW));
4275
Aric Stewart854bfc42005-06-24 11:33:02 +00004276 filename = MSI_RecordGetString(row,1);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004277 file = get_loaded_file( package, filename );
Aric Stewart854bfc42005-06-24 11:33:02 +00004278
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004279 if (!file)
Aric Stewart854bfc42005-06-24 11:33:02 +00004280 {
4281 ERR("Unable to find file id %s\n",debugstr_w(filename));
4282 return ERROR_SUCCESS;
4283 }
4284
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004285 len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
Aric Stewart854bfc42005-06-24 11:33:02 +00004286
Mike McCormackee034ba2005-09-20 11:59:14 +00004287 FullName = msi_alloc(len*sizeof(WCHAR));
Aric Stewart854bfc42005-06-24 11:33:02 +00004288 strcpyW(FullName,ExeStr);
Mike McCormacke18f8ab2005-08-23 10:03:17 +00004289 strcatW( FullName, file->TargetPath );
Aric Stewart854bfc42005-06-24 11:33:02 +00004290 strcatW(FullName,close);
4291
4292 TRACE("Registering %s\n",debugstr_w(FullName));
4293 brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
4294 &si, &info);
4295
4296 if (brc)
Rob Shearmancda469c2008-08-17 18:29:11 +01004297 {
4298 CloseHandle(info.hThread);
Aric Stewart854bfc42005-06-24 11:33:02 +00004299 msi_dialog_check_messages(info.hProcess);
Rob Shearmancda469c2008-08-17 18:29:11 +01004300 CloseHandle(info.hProcess);
4301 }
Aric Stewart854bfc42005-06-24 11:33:02 +00004302
Robert Shearmand2e48e02006-01-23 17:29:50 +01004303 uirow = MSI_CreateRecord( 2 );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004304 MSI_RecordSetStringW( uirow, 1, filename );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004305 uipath = strdupW( file->TargetPath );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004306 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
4307 MSI_RecordSetStringW( uirow, 2, uipath );
4308 ui_actiondata( package, szSelfRegModules, uirow );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004309 msiobj_release( &uirow->hdr );
Robert Shearmand2e48e02006-01-23 17:29:50 +01004310
Hans Leidekkera4be9412010-03-23 11:45:33 +01004311 msi_free( FullName );
4312 msi_free( uipath );
Aric Stewart854bfc42005-06-24 11:33:02 +00004313 return ERROR_SUCCESS;
4314}
4315
4316static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4317{
4318 UINT rc;
4319 MSIQUERY * view;
4320 static const WCHAR ExecSeqQuery[] =
4321 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4322 '`','S','e','l','f','R','e','g','`',0};
4323
Aric Stewart6269f002005-01-17 13:40:39 +00004324 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4325 if (rc != ERROR_SUCCESS)
4326 {
4327 TRACE("no SelfReg table\n");
4328 return ERROR_SUCCESS;
4329 }
4330
Aric Stewart854bfc42005-06-24 11:33:02 +00004331 MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
Aric Stewart6269f002005-01-17 13:40:39 +00004332 msiobj_release(&view->hdr);
Aric Stewart854bfc42005-06-24 11:33:02 +00004333
4334 return ERROR_SUCCESS;
Aric Stewart6269f002005-01-17 13:40:39 +00004335}
4336
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004337static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4338{
4339 static const WCHAR regsvr32[] =
4340 {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0};
4341 static const WCHAR close[] = {'\"',0};
4342 MSIPACKAGE *package = param;
4343 LPCWSTR filename;
4344 LPWSTR cmdline;
4345 MSIFILE *file;
4346 DWORD len;
4347 STARTUPINFOW si;
4348 PROCESS_INFORMATION pi;
4349 BOOL ret;
4350 MSIRECORD *uirow;
4351 LPWSTR uipath, p;
4352
4353 memset( &si, 0, sizeof(STARTUPINFOW) );
4354
4355 filename = MSI_RecordGetString( row, 1 );
4356 file = get_loaded_file( package, filename );
4357
4358 if (!file)
4359 {
4360 ERR("Unable to find file id %s\n", debugstr_w(filename));
4361 return ERROR_SUCCESS;
4362 }
4363
4364 len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2;
4365
4366 cmdline = msi_alloc( len * sizeof(WCHAR) );
4367 strcpyW( cmdline, regsvr32 );
4368 strcatW( cmdline, file->TargetPath );
4369 strcatW( cmdline, close );
4370
4371 TRACE("Unregistering %s\n", debugstr_w(cmdline));
4372
4373 ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi );
4374 if (ret)
4375 {
4376 CloseHandle( pi.hThread );
4377 msi_dialog_check_messages( pi.hProcess );
4378 CloseHandle( pi.hProcess );
4379 }
4380
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004381 uirow = MSI_CreateRecord( 2 );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004382 MSI_RecordSetStringW( uirow, 1, filename );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004383 uipath = strdupW( file->TargetPath );
Hans Leidekkera4be9412010-03-23 11:45:33 +01004384 if ((p = strrchrW( uipath,'\\' ))) *p = 0;
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004385 MSI_RecordSetStringW( uirow, 2, uipath );
4386 ui_actiondata( package, szSelfUnregModules, uirow );
4387 msiobj_release( &uirow->hdr );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004388
Hans Leidekkera4be9412010-03-23 11:45:33 +01004389 msi_free( cmdline );
4390 msi_free( uipath );
Hans Leidekkerf5af1ca2010-02-05 14:48:20 +01004391 return ERROR_SUCCESS;
4392}
4393
4394static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4395{
4396 UINT rc;
4397 MSIQUERY *view;
4398 static const WCHAR query[] =
4399 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4400 '`','S','e','l','f','R','e','g','`',0};
4401
4402 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4403 if (rc != ERROR_SUCCESS)
4404 {
4405 TRACE("no SelfReg table\n");
4406 return ERROR_SUCCESS;
4407 }
4408
4409 MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4410 msiobj_release( &view->hdr );
4411
4412 return ERROR_SUCCESS;
4413}
4414
Aric Stewart6269f002005-01-17 13:40:39 +00004415static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4416{
Mike McCormack1da28582005-08-22 14:09:17 +00004417 MSIFEATURE *feature;
Aric Stewart6269f002005-01-17 13:40:39 +00004418 UINT rc;
Hans Leidekker353035f2010-03-04 09:17:50 +01004419 HKEY hkey = NULL, userdata = NULL;
James Hawkins6ac08162007-08-09 11:38:48 -07004420
4421 if (!msi_check_publish(package))
4422 return ERROR_SUCCESS;
4423
James Hawkins0c01c582008-11-03 22:16:50 -06004424 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4425 &hkey, TRUE);
4426 if (rc != ERROR_SUCCESS)
4427 goto end;
4428
James Hawkinse3074342008-11-03 22:16:54 -06004429 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4430 &userdata, TRUE);
4431 if (rc != ERROR_SUCCESS)
4432 goto end;
James Hawkins9f11a5a2007-11-01 03:13:28 -05004433
Aric Stewart6269f002005-01-17 13:40:39 +00004434 /* here the guids are base 85 encoded */
Mike McCormack1da28582005-08-22 14:09:17 +00004435 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00004436 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004437 ComponentList *cl;
Aric Stewart6269f002005-01-17 13:40:39 +00004438 LPWSTR data = NULL;
4439 GUID clsid;
Aric Stewart6269f002005-01-17 13:40:39 +00004440 INT size;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004441 BOOL absent = FALSE;
Robert Shearmand2e48e02006-01-23 17:29:50 +01004442 MSIRECORD *uirow;
Aric Stewart6269f002005-01-17 13:40:39 +00004443
Hans Leidekkerc32d9d72010-02-16 11:45:05 +01004444 if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4445 feature->ActionRequest != INSTALLSTATE_SOURCE &&
4446 feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004447
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004448 size = 1;
Mike McCormack1da28582005-08-22 14:09:17 +00004449 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004450 {
4451 size += 21;
4452 }
Mike McCormack79ca56c2005-09-13 10:37:37 +00004453 if (feature->Feature_Parent)
Mike McCormack1da28582005-08-22 14:09:17 +00004454 size += strlenW( feature->Feature_Parent )+2;
Aric Stewart6269f002005-01-17 13:40:39 +00004455
Mike McCormackee034ba2005-09-20 11:59:14 +00004456 data = msi_alloc(size * sizeof(WCHAR));
Aric Stewart6269f002005-01-17 13:40:39 +00004457
4458 data[0] = 0;
Mike McCormack1da28582005-08-22 14:09:17 +00004459 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
Aric Stewart6269f002005-01-17 13:40:39 +00004460 {
Mike McCormack38d67a42005-08-22 09:15:23 +00004461 MSICOMPONENT* component = cl->component;
Aric Stewart6269f002005-01-17 13:40:39 +00004462 WCHAR buf[21];
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004463
Mike McCormack3a940112006-04-19 02:29:03 +09004464 buf[0] = 0;
Mike McCormackefcc1ec2005-09-12 12:07:15 +00004465 if (component->ComponentId)
Aric Stewartc5a14432005-05-18 17:46:12 +00004466 {
Mike McCormack3f2d5d72005-08-19 10:03:11 +00004467 TRACE("From %s\n",debugstr_w(component->ComponentId));
4468 CLSIDFromString(component->ComponentId, &clsid);
Aric Stewartc5a14432005-05-18 17:46:12 +00004469 encode_base85_guid(&clsid,buf);
4470 TRACE("to %s\n",debugstr_w(buf));
4471 strcatW(data,buf);
4472 }
Aric Stewart6269f002005-01-17 13:40:39 +00004473 }
James Hawkins9f11a5a2007-11-01 03:13:28 -05004474
Mike McCormack79ca56c2005-09-13 10:37:37 +00004475 if (feature->Feature_Parent)
Aric Stewart6269f002005-01-17 13:40:39 +00004476 {
4477 static const WCHAR sep[] = {'\2',0};
4478 strcatW(data,sep);
Mike McCormack1da28582005-08-22 14:09:17 +00004479 strcatW(data,feature->Feature_Parent);
Aric Stewart6269f002005-01-17 13:40:39 +00004480 }
4481
James Hawkins9f11a5a2007-11-01 03:13:28 -05004482 msi_reg_set_val_str( userdata, feature->Feature, data );
Mike McCormackee034ba2005-09-20 11:59:14 +00004483 msi_free(data);
Aric Stewart6269f002005-01-17 13:40:39 +00004484
Mike McCormack79ca56c2005-09-13 10:37:37 +00004485 size = 0;
4486 if (feature->Feature_Parent)
4487 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004488 if (!absent)
4489 {
Alexandre Julliard06bf8ea2008-04-22 17:05:05 +02004490 size += sizeof(WCHAR);
James Hawkins2a180e02008-06-19 00:32:59 -05004491 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
Mikhail Maroukhine86f76d22010-03-27 20:48:20 +06004492 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004493 }
4494 else
4495 {
Mike McCormack79ca56c2005-09-13 10:37:37 +00004496 size += 2*sizeof(WCHAR);
Mike McCormackee034ba2005-09-20 11:59:14 +00004497 data = msi_alloc(size);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004498 data[0] = 0x6;
Mike McCormack79ca56c2005-09-13 10:37:37 +00004499 data[1] = 0;
4500 if (feature->Feature_Parent)
4501 strcpyW( &data[1], feature->Feature_Parent );
James Hawkins2a180e02008-06-19 00:32:59 -05004502 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
Mike McCormack16466af2005-07-06 10:33:30 +00004503 (LPBYTE)data,size);
Mike McCormackee034ba2005-09-20 11:59:14 +00004504 msi_free(data);
Aric Stewartb39d8fc2005-05-13 13:56:39 +00004505 }
Robert Shearmand2e48e02006-01-23 17:29:50 +01004506
4507 /* the UI chunk */
4508 uirow = MSI_CreateRecord( 1 );
4509 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4510 ui_actiondata( package, szPublishFeatures, uirow);
4511 msiobj_release( &uirow->hdr );
4512 /* FIXME: call ui_progress? */
Aric Stewart6269f002005-01-17 13:40:39 +00004513 }
4514
Aric Stewart6269f002005-01-17 13:40:39 +00004515end:
James Hawkins2a180e02008-06-19 00:32:59 -05004516 RegCloseKey(hkey);
4517 RegCloseKey(userdata);
Aric Stewart6269f002005-01-17 13:40:39 +00004518 return rc;
4519}
4520
James Hawkins6ac08162007-08-09 11:38:48 -07004521static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4522{
4523 UINT r;
4524 HKEY hkey;
Hans Leidekker18a85ca2010-03-23 11:47:19 +01004525 MSIRECORD *uirow;
James Hawkins6ac08162007-08-09 11:38:48 -07004526
4527 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4528
James Hawkins0c01c582008-11-03 22:16:50 -06004529 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4530 &hkey, FALSE);
James Hawkins6ac08162007-08-09 11:38:48 -07004531 if (r == ERROR_SUCCESS)
4532 {
4533 RegDeleteValueW(hkey, feature->Feature);
4534 RegCloseKey(hkey);
4535 }
4536
James Hawkinse3074342008-11-03 22:16:54 -06004537 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4538 &hkey, FALSE);
James Hawkins6ac08162007-08-09 11:38:48 -07004539 if (r == ERROR_SUCCESS)
4540 {
4541 RegDeleteValueW(hkey, feature->Feature);
4542 RegCloseKey(hkey);
4543 }
4544
Hans Leidekker18a85ca2010-03-23 11:47:19 +01004545 uirow = MSI_CreateRecord( 1 );
4546 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4547 ui_actiondata( package, szUnpublishFeatures, uirow );
4548 msiobj_release( &uirow->hdr );
4549
James Hawkins6ac08162007-08-09 11:38:48 -07004550 return ERROR_SUCCESS;
4551}
4552
4553static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4554{
4555 MSIFEATURE *feature;
4556
James Hawkinsccdf5782007-11-01 03:14:18 -05004557 if (!msi_check_unpublish(package))
James Hawkins6ac08162007-08-09 11:38:48 -07004558 return ERROR_SUCCESS;
4559
4560 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4561 {
4562 msi_unpublish_feature(package, feature);
4563 }
4564
4565 return ERROR_SUCCESS;
4566}
4567
James Hawkins45de8962008-06-19 00:36:10 -05004568static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
Mike McCormackba293ee2005-10-27 12:08:16 +00004569{
James Hawkins45de8962008-06-19 00:36:10 -05004570 SYSTEMTIME systime;
4571 DWORD size, langid;
Hans Leidekker41a7f022010-05-11 14:03:08 +02004572 WCHAR date[9], *val, *buffer;
4573 const WCHAR *prop, *key;
James Hawkins45de8962008-06-19 00:36:10 -05004574
4575 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4576 static const WCHAR szWindowsInstaller[] =
4577 {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4578 static const WCHAR modpath_fmt[] =
4579 {'M','s','i','E','x','e','c','.','e','x','e',' ',
4580 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4581 static const WCHAR szModifyPath[] =
4582 {'M','o','d','i','f','y','P','a','t','h',0};
4583 static const WCHAR szUninstallString[] =
4584 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4585 static const WCHAR szEstimatedSize[] =
4586 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4587 static const WCHAR szProductLanguage[] =
4588 {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4589 static const WCHAR szProductVersion[] =
4590 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
James Hawkins45de8962008-06-19 00:36:10 -05004591 static const WCHAR szDisplayVersion[] =
4592 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
Hans Leidekker41a7f022010-05-11 14:03:08 +02004593 static const WCHAR szInstallSource[] =
4594 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4595 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4596 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4597 static const WCHAR szAuthorizedCDFPrefix[] =
4598 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4599 static const WCHAR szARPCONTACT[] =
4600 {'A','R','P','C','O','N','T','A','C','T',0};
4601 static const WCHAR szContact[] =
4602 {'C','o','n','t','a','c','t',0};
4603 static const WCHAR szARPCOMMENTS[] =
4604 {'A','R','P','C','O','M','M','E','N','T','S',0};
4605 static const WCHAR szComments[] =
4606 {'C','o','m','m','e','n','t','s',0};
4607 static const WCHAR szProductName[] =
4608 {'P','r','o','d','u','c','t','N','a','m','e',0};
4609 static const WCHAR szDisplayName[] =
4610 {'D','i','s','p','l','a','y','N','a','m','e',0};
4611 static const WCHAR szARPHELPLINK[] =
4612 {'A','R','P','H','E','L','P','L','I','N','K',0};
4613 static const WCHAR szHelpLink[] =
4614 {'H','e','l','p','L','i','n','k',0};
4615 static const WCHAR szARPHELPTELEPHONE[] =
4616 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4617 static const WCHAR szHelpTelephone[] =
4618 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4619 static const WCHAR szARPINSTALLLOCATION[] =
4620 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4621 static const WCHAR szInstallLocation[] =
4622 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4623 static const WCHAR szManufacturer[] =
4624 {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4625 static const WCHAR szPublisher[] =
4626 {'P','u','b','l','i','s','h','e','r',0};
4627 static const WCHAR szARPREADME[] =
4628 {'A','R','P','R','E','A','D','M','E',0};
4629 static const WCHAR szReadme[] =
4630 {'R','e','a','d','M','e',0};
4631 static const WCHAR szARPSIZE[] =
4632 {'A','R','P','S','I','Z','E',0};
4633 static const WCHAR szSize[] =
4634 {'S','i','z','e',0};
4635 static const WCHAR szARPURLINFOABOUT[] =
4636 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4637 static const WCHAR szURLInfoAbout[] =
4638 {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4639 static const WCHAR szARPURLUPDATEINFO[] =
4640 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4641 static const WCHAR szURLUpdateInfo[] =
4642 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
James Hawkins45de8962008-06-19 00:36:10 -05004643
Hans Leidekker41a7f022010-05-11 14:03:08 +02004644 static const WCHAR *propval[] = {
4645 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4646 szARPCONTACT, szContact,
4647 szARPCOMMENTS, szComments,
4648 szProductName, szDisplayName,
4649 szARPHELPLINK, szHelpLink,
4650 szARPHELPTELEPHONE, szHelpTelephone,
4651 szARPINSTALLLOCATION, szInstallLocation,
4652 cszSourceDir, szInstallSource,
4653 szManufacturer, szPublisher,
4654 szARPREADME, szReadme,
4655 szARPSIZE, szSize,
4656 szARPURLINFOABOUT, szURLInfoAbout,
4657 szARPURLUPDATEINFO, szURLUpdateInfo,
4658 NULL
Mike McCormackba293ee2005-10-27 12:08:16 +00004659 };
Hans Leidekker41a7f022010-05-11 14:03:08 +02004660 const WCHAR **p = propval;
Mike McCormackba293ee2005-10-27 12:08:16 +00004661
James Hawkins45de8962008-06-19 00:36:10 -05004662 while (*p)
Mike McCormackba293ee2005-10-27 12:08:16 +00004663 {
Hans Leidekker41a7f022010-05-11 14:03:08 +02004664 prop = *p++;
4665 key = *p++;
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004666 val = msi_dup_property(package->db, prop);
James Hawkins45de8962008-06-19 00:36:10 -05004667 msi_reg_set_val_str(hkey, key, val);
Mike McCormackba293ee2005-10-27 12:08:16 +00004668 msi_free(val);
Mike McCormackba293ee2005-10-27 12:08:16 +00004669 }
James Hawkins45de8962008-06-19 00:36:10 -05004670
4671 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4672
4673 size = deformat_string(package, modpath_fmt, &buffer);
4674 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4675 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4676 msi_free(buffer);
4677
4678 /* FIXME: Write real Estimated Size when we have it */
4679 msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4680
James Hawkins45de8962008-06-19 00:36:10 -05004681 GetLocalTime(&systime);
4682 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4683 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4684
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004685 langid = msi_get_property_int(package->db, szProductLanguage, 0);
James Hawkins45de8962008-06-19 00:36:10 -05004686 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4687
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004688 buffer = msi_dup_property(package->db, szProductVersion);
James Hawkins45de8962008-06-19 00:36:10 -05004689 msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4690 if (buffer)
4691 {
4692 DWORD verdword = msi_version_str_to_dword(buffer);
4693
4694 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4695 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4696 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4697 msi_free(buffer);
4698 }
4699
Mike McCormackba293ee2005-10-27 12:08:16 +00004700 return ERROR_SUCCESS;
4701}
4702
Aric Stewart2cae30b2005-01-19 19:07:40 +00004703static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4704{
James Hawkins45de8962008-06-19 00:36:10 -05004705 WCHAR squashed_pc[SQUISH_GUID_SIZE];
Hans Leidekker4341f182010-03-05 12:28:11 +01004706 MSIRECORD *uirow;
Aric Stewart36a01502005-06-08 19:07:52 +00004707 LPWSTR upgrade_code;
James Hawkins45de8962008-06-19 00:36:10 -05004708 HKEY hkey, props;
4709 HKEY upgrade;
4710 UINT rc;
4711
4712 static const WCHAR szUpgradeCode[] = {
4713 'U','p','g','r','a','d','e','C','o','d','e',0};
James Hawkins0e44e092007-07-02 20:21:58 -07004714
4715 /* FIXME: also need to publish if the product is in advertise mode */
4716 if (!msi_check_publish(package))
4717 return ERROR_SUCCESS;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004718
James Hawkins45de8962008-06-19 00:36:10 -05004719 rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004720 if (rc != ERROR_SUCCESS)
Mike McCormackba293ee2005-10-27 12:08:16 +00004721 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004722
James Hawkinsb5e3e192008-12-14 21:07:14 -06004723 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4724 NULL, &props, TRUE);
4725 if (rc != ERROR_SUCCESS)
4726 goto done;
James Hawkinsd52f48f2008-03-06 16:12:40 -06004727
Hans Leidekker8dd3d382009-10-20 14:09:53 +02004728 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4729 msi_free( package->db->localfile );
4730 package->db->localfile = NULL;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004731
James Hawkins45de8962008-06-19 00:36:10 -05004732 rc = msi_publish_install_properties(package, hkey);
4733 if (rc != ERROR_SUCCESS)
4734 goto done;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004735
James Hawkins45de8962008-06-19 00:36:10 -05004736 rc = msi_publish_install_properties(package, props);
4737 if (rc != ERROR_SUCCESS)
4738 goto done;
Aric Stewart36a01502005-06-08 19:07:52 +00004739
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004740 upgrade_code = msi_dup_property(package->db, szUpgradeCode);
Aric Stewart36a01502005-06-08 19:07:52 +00004741 if (upgrade_code)
4742 {
James Hawkins45de8962008-06-19 00:36:10 -05004743 MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4744 squash_guid(package->ProductCode, squashed_pc);
4745 msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4746 RegCloseKey(upgrade);
Mike McCormackee034ba2005-09-20 11:59:14 +00004747 msi_free(upgrade_code);
Aric Stewart36a01502005-06-08 19:07:52 +00004748 }
James Hawkinsbcba82d2008-04-05 06:02:04 -05004749
James Hawkins45de8962008-06-19 00:36:10 -05004750done:
Hans Leidekker4341f182010-03-05 12:28:11 +01004751 uirow = MSI_CreateRecord( 1 );
4752 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4753 ui_actiondata( package, szRegisterProduct, uirow );
4754 msiobj_release( &uirow->hdr );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004755
Hans Leidekker4341f182010-03-05 12:28:11 +01004756 RegCloseKey(hkey);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004757 return ERROR_SUCCESS;
4758}
4759
4760static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4761{
Mike McCormacka977b2c2005-11-03 09:56:29 +00004762 return execute_script(package,INSTALL_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004763}
4764
James Hawkins624bbbe2007-07-02 20:20:54 -07004765static UINT msi_unpublish_product(MSIPACKAGE *package)
4766{
James Hawkinscdb33f82008-06-23 23:02:54 -05004767 LPWSTR upgrade;
James Hawkins624bbbe2007-07-02 20:20:54 -07004768 LPWSTR remove = NULL;
4769 LPWSTR *features = NULL;
4770 BOOL full_uninstall = TRUE;
4771 MSIFEATURE *feature;
Hans Leidekker920fc342010-05-04 09:07:39 +02004772 MSIPATCHINFO *patch;
James Hawkins624bbbe2007-07-02 20:20:54 -07004773
James Hawkinscdb33f82008-06-23 23:02:54 -05004774 static const WCHAR szUpgradeCode[] =
4775 {'U','p','g','r','a','d','e','C','o','d','e',0};
James Hawkins624bbbe2007-07-02 20:20:54 -07004776
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004777 remove = msi_dup_property(package->db, szRemove);
James Hawkins624bbbe2007-07-02 20:20:54 -07004778 if (!remove)
4779 return ERROR_SUCCESS;
4780
4781 features = msi_split_string(remove, ',');
4782 if (!features)
4783 {
4784 msi_free(remove);
4785 ERR("REMOVE feature list is empty!\n");
4786 return ERROR_FUNCTION_FAILED;
4787 }
4788
4789 if (!lstrcmpW(features[0], szAll))
4790 full_uninstall = TRUE;
4791 else
4792 {
4793 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4794 {
4795 if (feature->Action != INSTALLSTATE_ABSENT)
4796 full_uninstall = FALSE;
4797 }
4798 }
4799
4800 if (!full_uninstall)
4801 goto done;
4802
4803 MSIREG_DeleteProductKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004804 MSIREG_DeleteUserDataProductKey(package->ProductCode);
James Hawkinsf6b27672007-11-13 00:47:21 -06004805 MSIREG_DeleteUninstallKey(package->ProductCode);
James Hawkins624bbbe2007-07-02 20:20:54 -07004806
James Hawkins38106ac2008-07-28 18:46:32 -05004807 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4808 {
4809 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4810 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4811 }
4812 else
4813 {
4814 MSIREG_DeleteUserProductKey(package->ProductCode);
4815 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4816 }
4817
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004818 upgrade = msi_dup_property(package->db, szUpgradeCode);
James Hawkinscdb33f82008-06-23 23:02:54 -05004819 if (upgrade)
4820 {
4821 MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4822 msi_free(upgrade);
4823 }
4824
Hans Leidekker920fc342010-05-04 09:07:39 +02004825 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4826 {
4827 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4828 }
4829
James Hawkins624bbbe2007-07-02 20:20:54 -07004830done:
4831 msi_free(remove);
4832 msi_free(features);
4833 return ERROR_SUCCESS;
4834}
4835
Aric Stewart2cae30b2005-01-19 19:07:40 +00004836static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4837{
Aric Stewart9cd707d2005-05-27 19:24:22 +00004838 UINT rc;
4839
James Hawkins624bbbe2007-07-02 20:20:54 -07004840 rc = msi_unpublish_product(package);
4841 if (rc != ERROR_SUCCESS)
4842 return rc;
4843
Francois Gouget1ccf9442006-11-12 19:51:37 +01004844 /* turn off scheduling */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004845 package->script->CurrentlyScripting= FALSE;
4846
Aric Stewart54c67dd2005-01-25 20:17:09 +00004847 /* first do the same as an InstallExecute */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004848 rc = ACTION_InstallExecute(package);
4849 if (rc != ERROR_SUCCESS)
4850 return rc;
Aric Stewart54c67dd2005-01-25 20:17:09 +00004851
4852 /* then handle Commit Actions */
Aric Stewart9cd707d2005-05-27 19:24:22 +00004853 rc = execute_script(package,COMMIT_SCRIPT);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004854
Aric Stewart9cd707d2005-05-27 19:24:22 +00004855 return rc;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004856}
4857
James Hawkinsc2e91582007-05-29 12:03:05 -07004858UINT ACTION_ForceReboot(MSIPACKAGE *package)
Aric Stewart2cae30b2005-01-19 19:07:40 +00004859{
4860 static const WCHAR RunOnce[] = {
4861 'S','o','f','t','w','a','r','e','\\',
4862 'M','i','c','r','o','s','o','f','t','\\',
4863 'W','i','n','d','o','w','s','\\',
4864 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004865 'R','u','n','O','n','c','e',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004866 static const WCHAR InstallRunOnce[] = {
4867 'S','o','f','t','w','a','r','e','\\',
4868 'M','i','c','r','o','s','o','f','t','\\',
4869 'W','i','n','d','o','w','s','\\',
4870 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4871 'I','n','s','t','a','l','l','e','r','\\',
Mike McCormack09b82642005-02-22 19:31:45 +00004872 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
Aric Stewart2cae30b2005-01-19 19:07:40 +00004873
4874 static const WCHAR msiexec_fmt[] = {
Juan Lang014ad3b2005-03-01 10:41:52 +00004875 '%','s',
Aric Stewart2cae30b2005-01-19 19:07:40 +00004876 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
4877 '\"','%','s','\"',0};
4878 static const WCHAR install_fmt[] = {
4879 '/','I',' ','\"','%','s','\"',' ',
4880 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
4881 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
Juan Lang014ad3b2005-03-01 10:41:52 +00004882 WCHAR buffer[256], sysdir[MAX_PATH];
Aric Stewartadaef112005-07-07 20:27:06 +00004883 HKEY hkey;
Mike McCormack4db02cd2005-09-15 14:58:38 +00004884 WCHAR squished_pc[100];
Aric Stewart2cae30b2005-01-19 19:07:40 +00004885
Aric Stewartadaef112005-07-07 20:27:06 +00004886 squash_guid(package->ProductCode,squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004887
Juan Lang014ad3b2005-03-01 10:41:52 +00004888 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
Aric Stewart2cae30b2005-01-19 19:07:40 +00004889 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
Juan Lang014ad3b2005-03-01 10:41:52 +00004890 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
4891 squished_pc);
Aric Stewart2cae30b2005-01-19 19:07:40 +00004892
Mike McCormack4db02cd2005-09-15 14:58:38 +00004893 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004894 RegCloseKey(hkey);
4895
4896 TRACE("Reboot command %s\n",debugstr_w(buffer));
4897
4898 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
Aric Stewartadaef112005-07-07 20:27:06 +00004899 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00004900
Mike McCormack4db02cd2005-09-15 14:58:38 +00004901 msi_reg_set_val_str( hkey, squished_pc, buffer );
Aric Stewart2cae30b2005-01-19 19:07:40 +00004902 RegCloseKey(hkey);
4903
Aric Stewart68b07492005-01-25 11:05:37 +00004904 return ERROR_INSTALL_SUSPEND;
Aric Stewart2cae30b2005-01-19 19:07:40 +00004905}
4906
James Hawkins563a50a2006-10-09 00:05:04 -07004907static UINT ACTION_ResolveSource(MSIPACKAGE* package)
Aric Stewart90c57392005-01-31 16:23:12 +00004908{
Mike McCormackb9211182006-11-20 16:27:36 +09004909 DWORD attrib;
Aric Stewart94d68182005-08-15 20:50:06 +00004910 UINT rc;
Mike McCormackfc564232006-11-20 16:17:03 +09004911
Aric Stewart90c57392005-01-31 16:23:12 +00004912 /*
Mike McCormackfc564232006-11-20 16:17:03 +09004913 * We are currently doing what should be done here in the top level Install
4914 * however for Administrative and uninstalls this step will be needed
Aric Stewart90c57392005-01-31 16:23:12 +00004915 */
Aric Stewart94d68182005-08-15 20:50:06 +00004916 if (!package->PackagePath)
4917 return ERROR_SUCCESS;
4918
James Hawkinsc777d302008-01-05 13:45:13 -07004919 msi_set_sourcedir_props(package, TRUE);
James Hawkinsc5075432006-10-10 13:39:50 -07004920
James Hawkinse28cedf2008-01-05 13:48:32 -07004921 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004922 if (attrib == INVALID_FILE_ATTRIBUTES)
4923 {
4924 LPWSTR prompt;
4925 LPWSTR msg;
4926 DWORD size = 0;
4927
4928 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004929 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004930 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
4931 if (rc == ERROR_MORE_DATA)
4932 {
Mike McCormackee034ba2005-09-20 11:59:14 +00004933 prompt = msi_alloc(size * sizeof(WCHAR));
Aric Stewart94d68182005-08-15 20:50:06 +00004934 MsiSourceListGetInfoW(package->ProductCode, NULL,
James Hawkins82517d62008-04-05 00:10:02 -05004935 package->Context, MSICODE_PRODUCT,
Aric Stewart94d68182005-08-15 20:50:06 +00004936 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
4937 }
4938 else
James Hawkinse28cedf2008-01-05 13:48:32 -07004939 prompt = strdupW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004940
4941 msg = generate_error_string(package,1302,1,prompt);
4942 while(attrib == INVALID_FILE_ATTRIBUTES)
4943 {
4944 rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
4945 if (rc == IDCANCEL)
4946 {
4947 rc = ERROR_INSTALL_USEREXIT;
4948 break;
4949 }
James Hawkinse28cedf2008-01-05 13:48:32 -07004950 attrib = GetFileAttributesW(package->db->path);
Aric Stewart94d68182005-08-15 20:50:06 +00004951 }
Mike McCormackee034ba2005-09-20 11:59:14 +00004952 msi_free(prompt);
Aric Stewart94d68182005-08-15 20:50:06 +00004953 rc = ERROR_SUCCESS;
4954 }
4955 else
4956 return ERROR_SUCCESS;
4957
4958 return rc;
Aric Stewart90c57392005-01-31 16:23:12 +00004959}
4960
Aric Stewartc7e88e02005-02-10 17:09:44 +00004961static UINT ACTION_RegisterUser(MSIPACKAGE *package)
4962{
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004963 HKEY hkey = 0;
4964 LPWSTR buffer, productid = NULL;
4965 UINT i, rc = ERROR_SUCCESS;
4966 MSIRECORD *uirow;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004967
4968 static const WCHAR szPropKeys[][80] =
4969 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004970 {'P','r','o','d','u','c','t','I','D',0},
4971 {'U','S','E','R','N','A','M','E',0},
4972 {'C','O','M','P','A','N','Y','N','A','M','E',0},
4973 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004974 };
4975
4976 static const WCHAR szRegKeys[][80] =
4977 {
Aric Stewart8e233e92005-03-01 11:45:19 +00004978 {'P','r','o','d','u','c','t','I','D',0},
4979 {'R','e','g','O','w','n','e','r',0},
4980 {'R','e','g','C','o','m','p','a','n','y',0},
4981 {0},
Aric Stewartc7e88e02005-02-10 17:09:44 +00004982 };
4983
James Hawkinsd52f48f2008-03-06 16:12:40 -06004984 if (msi_check_unpublish(package))
4985 {
4986 MSIREG_DeleteUserDataProductKey(package->ProductCode);
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004987 goto end;
James Hawkinsd52f48f2008-03-06 16:12:40 -06004988 }
4989
Hans Leidekker186f4ef2010-04-21 11:37:54 +02004990 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
Aric Stewartc7e88e02005-02-10 17:09:44 +00004991 if (!productid)
Hans Leidekkerab9a1812010-03-05 12:28:34 +01004992 goto end;
Aric Stewartc7e88e02005-02-10 17:09:44 +00004993
James Hawkinsb5e3e192008-12-14 21:07:14 -06004994 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4995 NULL, &hkey, TRUE);
Aric Stewartc7e88e02005-02-10 17:09:44 +00004996 if (rc != ERROR_SUCCESS)
4997 goto end;
4998
Mike McCormack67189f92005-09-16 18:45:19 +00004999 for( i = 0; szPropKeys[i][0]; i++ )
Aric Stewartc7e88e02005-02-10 17:09:44 +00005000 {
Hans Leidekker186f4ef2010-04-21 11:37:54 +02005001 buffer = msi_dup_property( package->db, szPropKeys[i] );
Mike McCormack4db02cd2005-09-15 14:58:38 +00005002 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
Mike McCormackee034ba2005-09-20 11:59:14 +00005003 msi_free( buffer );
Aric Stewartc7e88e02005-02-10 17:09:44 +00005004 }
5005
5006end:
Hans Leidekkerab9a1812010-03-05 12:28:34 +01005007 uirow = MSI_CreateRecord( 1 );
5008 MSI_RecordSetStringW( uirow, 1, productid );
5009 ui_actiondata( package, szRegisterUser, uirow );
5010 msiobj_release( &uirow->hdr );
5011
Mike McCormackee034ba2005-09-20 11:59:14 +00005012 msi_free(productid);
Aric Stewartc7e88e02005-02-10 17:09:44 +00005013 RegCloseKey(hkey);
James Hawkinsd52f48f2008-03-06 16:12:40 -06005014 return rc;
Aric Stewartc7e88e02005-02-10 17:09:44 +00005015}
5016
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00005017
5018static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5019{
5020 UINT rc;
Aric Stewart25f1e752005-06-24 12:14:52 +00005021
Aric Stewartc9802932005-06-30 20:45:43 +00005022 package->script->InWhatSequence |= SEQUENCE_EXEC;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00005023 rc = ACTION_ProcessExecSequence(package,FALSE);
Aric Stewartb6bc6aa2005-02-24 12:47:43 +00005024 return rc;
5025}
5026
Aric Stewart0af24872005-02-25 14:00:09 +00005027
Aric Stewart072c5e52005-04-20 12:50:05 +00005028static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5029{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005030 MSIPACKAGE *package = param;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005031 LPCWSTR compgroupid, component, feature, qualifier, text;
5032 LPWSTR advertise = NULL, output = NULL;
Hans Leidekker353035f2010-03-04 09:17:50 +01005033 HKEY hkey = NULL;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005034 UINT rc;
Mike McCormack38d67a42005-08-22 09:15:23 +00005035 MSICOMPONENT *comp;
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005036 MSIFEATURE *feat;
5037 DWORD sz;
Robert Shearmand2e48e02006-01-23 17:29:50 +01005038 MSIRECORD *uirow;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00005039
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005040 feature = MSI_RecordGetString(rec, 5);
5041 feat = get_loaded_feature(package, feature);
5042 if (!feat)
Hans Leidekker598c5422010-02-16 11:44:47 +01005043 return ERROR_SUCCESS;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00005044
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005045 if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5046 feat->ActionRequest != INSTALLSTATE_SOURCE &&
5047 feat->ActionRequest != INSTALLSTATE_ADVERTISED)
Aric Stewartb39d8fc2005-05-13 13:56:39 +00005048 {
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005049 TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5050 feat->Action = feat->Installed;
Aric Stewartb39d8fc2005-05-13 13:56:39 +00005051 return ERROR_SUCCESS;
5052 }
Aric Stewart072c5e52005-04-20 12:50:05 +00005053
Hans Leidekkerd95e3eb2010-02-17 09:55:03 +01005054 component = MSI_RecordGetString(rec, 3);
5055 comp = get_loaded_component(package, component);
5056 if (!comp)
5057 return ERROR_SUCCESS;
5058
Aric Stewart09b0aba2005-06-09 20:30:59 +00005059 compgroupid = MSI_RecordGetString(rec,1);
Robert Shearmand2e48e02006-01-23 17:29:50 +01005060 qualifier = MSI_RecordGetString(rec,2);
Aric Stewart072c5e52005-04-20 12:50:05 +00005061
5062 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5063 if (rc != ERROR_SUCCESS)
5064 goto end;
5065
Aric Stewart09b0aba2005-06-09 20:30:59 +00005066 text = MSI_RecordGetString(rec,4);
Mike McCormack38d67a42005-08-22 09:15:23 +00005067 advertise = create_component_advertise_string(package, comp, feature);
Aric Stewart072c5e52005-04-20 12:50:05 +00005068
Aric Stewart6f43c182005-05-26 12:24:28 +00005069 sz = strlenW(advertise);
5070
Aric Stewart072c5e52005-04-20 12:50:05 +00005071 if (text)
5072 sz += lstrlenW(text);
Aric Stewart072c5e52005-04-20 12:50:05 +00005073
5074 sz+=3;
5075 sz *= sizeof(WCHAR);
5076
Mike McCormack3a940112006-04-19 02:29:03 +09005077 output = msi_alloc_zero(sz);
Aric Stewart6f43c182005-05-26 12:24:28 +00005078 strcpyW(output,advertise);
Mike McCormack470f23d2005-09-22 10:56:26 +00005079 msi_free(advertise);
Aric Stewart072c5e52005-04-20 12:50:05 +00005080
5081 if (text)
5082 strcatW(output,text);
5083
Mike McCormack4db02cd2005-09-15 14:58:38 +00005084 msi_reg_set_val_multi_str( hkey, qualifier, output );
Aric Stewart072c5e52005-04-20 12:50:05 +00005085
5086end:
5087 RegCloseKey(hkey);
Mike McCormackee034ba2005-09-20 11:59:14 +00005088 msi_free(output);
Robert Shearmand2e48e02006-01-23 17:29:50 +01005089
5090 /* the UI chunk */
5091 uirow = MSI_CreateRecord( 2 );
5092 MSI_RecordSetStringW( uirow, 1, compgroupid );
5093 MSI_RecordSetStringW( uirow, 2, qualifier);
5094 ui_actiondata( package, szPublishComponents, uirow);
5095 msiobj_release( &uirow->hdr );
5096 /* FIXME: call ui_progress? */
5097
Aric Stewart072c5e52005-04-20 12:50:05 +00005098 return rc;
5099}
5100
5101/*
5102 * At present I am ignorning the advertised components part of this and only
5103 * focusing on the qualified component sets
5104 */
5105static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5106{
5107 UINT rc;
5108 MSIQUERY * view;
5109 static const WCHAR ExecSeqQuery[] =
5110 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
Aric Stewart98e38082005-05-20 09:40:42 +00005111 '`','P','u','b','l','i','s','h',
5112 'C','o','m','p','o','n','e','n','t','`',0};
Aric Stewart072c5e52005-04-20 12:50:05 +00005113
5114 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5115 if (rc != ERROR_SUCCESS)
5116 return ERROR_SUCCESS;
5117
5118 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5119 msiobj_release(&view->hdr);
5120
5121 return rc;
5122}
Mike McCormack202166c2005-09-23 10:09:18 +00005123
Hans Leidekker0f0e81d2010-02-17 09:55:31 +01005124static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5125{
5126 static const WCHAR szInstallerComponents[] = {
5127 'S','o','f','t','w','a','r','e','\\',
5128 'M','i','c','r','o','s','o','f','t','\\',
5129 'I','n','s','t','a','l','l','e','r','\\',
5130 'C','o','m','p','o','n','e','n','t','s','\\',0};
5131
5132 MSIPACKAGE *package = param;
5133 LPCWSTR compgroupid, component, feature, qualifier;
5134 MSICOMPONENT *comp;
5135 MSIFEATURE *feat;
5136 MSIRECORD *uirow;
5137 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5138 LONG res;
5139
5140 feature = MSI_RecordGetString( rec, 5 );
5141 feat = get_loaded_feature( package, feature );
5142 if (!feat)
5143 return ERROR_SUCCESS;
5144
5145 if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5146 {
5147 TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5148 feat->Action = feat->Installed;
5149 return ERROR_SUCCESS;
5150 }
5151
5152 component = MSI_RecordGetString( rec, 3 );
5153 comp = get_loaded_component( package, component );
5154 if (!comp)
5155 return ERROR_SUCCESS;
5156
5157 compgroupid = MSI_RecordGetString( rec, 1 );
5158 qualifier = MSI_RecordGetString( rec, 2 );
5159
5160 squash_guid( compgroupid, squashed );
5161 strcpyW( keypath, szInstallerComponents );
5162 strcatW( keypath, squashed );
5163
5164 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5165 if (res != ERROR_SUCCESS)
5166 {
5167 WARN("Unable to delete component key %d\n", res);
5168 }
5169
5170 uirow = MSI_CreateRecord( 2 );
5171 MSI_RecordSetStringW( uirow, 1, compgroupid );
5172 MSI_RecordSetStringW( uirow, 2, qualifier );
5173 ui_actiondata( package, szUnpublishComponents, uirow );
5174 msiobj_release( &uirow->hdr );
5175
5176 return ERROR_SUCCESS;
5177}
5178
5179static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5180{
5181 UINT rc;
5182 MSIQUERY *view;
5183 static const WCHAR query[] =
5184 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5185 '`','P','u','b','l','i','s','h',
5186 'C','o','m','p','o','n','e','n','t','`',0};
5187
5188 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5189 if (rc != ERROR_SUCCESS)
5190 return ERROR_SUCCESS;
5191
5192 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5193 msiobj_release( &view->hdr );
5194
5195 return rc;
5196}
5197
James Hawkins9bc12ad2006-10-19 15:49:54 -07005198static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5199{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005200 MSIPACKAGE *package = param;
James Hawkins9bc12ad2006-10-19 15:49:54 -07005201 MSIRECORD *row;
5202 MSIFILE *file;
5203 SC_HANDLE hscm, service = NULL;
James Hawkinsde4cab22008-03-11 18:08:57 -05005204 LPCWSTR comp, depends, pass;
Marcus Meissnerdb71fb12008-03-13 21:54:48 +01005205 LPWSTR name = NULL, disp = NULL;
James Hawkins9bc12ad2006-10-19 15:49:54 -07005206 LPCWSTR load_order, serv_name, key;
5207 DWORD serv_type, start_type;
5208 DWORD err_control;
5209
5210 static const WCHAR query[] =
5211 {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5212 '`','C','o','m','p','o','n','e','n','t','`',' ',
5213 'W','H','E','R','E',' ',
5214 '`','C','o','m','p','o','n','e','n','t','`',' ',
5215 '=','\'','%','s','\'',0};
5216
5217 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5218 if (!hscm)
5219 {
5220 ERR("Failed to open the SC Manager!\n");
5221 goto done;
5222 }
5223
5224 start_type = MSI_RecordGetInteger(rec, 5);
5225 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5226 goto done;
5227
5228 depends = MSI_RecordGetString(rec, 8);
5229 if (depends && *depends)
5230 FIXME("Dependency list unhandled!\n");
5231
James Hawkinsde4cab22008-03-11 18:08:57 -05005232 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5233 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005234 serv_type = MSI_RecordGetInteger(rec, 4);
5235 err_control = MSI_RecordGetInteger(rec, 6);
5236 load_order = MSI_RecordGetString(rec, 7);
5237 serv_name = MSI_RecordGetString(rec, 9);
5238 pass = MSI_RecordGetString(rec, 10);
5239 comp = MSI_RecordGetString(rec, 12);
5240
5241 /* fetch the service path */
5242 row = MSI_QueryGetRecord(package->db, query, comp);
5243 if (!row)
5244 {
5245 ERR("Control query failed!\n");
5246 goto done;
5247 }
5248
5249 key = MSI_RecordGetString(row, 6);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005250
5251 file = get_loaded_file(package, key);
James Hawkinsb6cfc402007-10-23 03:06:59 -05005252 msiobj_release(&row->hdr);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005253 if (!file)
5254 {
5255 ERR("Failed to load the service file\n");
5256 goto done;
5257 }
5258
5259 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5260 start_type, err_control, file->TargetPath,
5261 load_order, NULL, NULL, serv_name, pass);
5262 if (!service)
5263 {
5264 if (GetLastError() != ERROR_SERVICE_EXISTS)
5265 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5266 }
5267
5268done:
5269 CloseServiceHandle(service);
5270 CloseServiceHandle(hscm);
James Hawkinsde4cab22008-03-11 18:08:57 -05005271 msi_free(name);
5272 msi_free(disp);
James Hawkins9bc12ad2006-10-19 15:49:54 -07005273
5274 return ERROR_SUCCESS;
5275}
5276
5277static UINT ACTION_InstallServices( MSIPACKAGE *package )
5278{
5279 UINT rc;
5280 MSIQUERY * view;
5281 static const WCHAR ExecSeqQuery[] =
5282 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5283 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5284
5285 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5286 if (rc != ERROR_SUCCESS)
5287 return ERROR_SUCCESS;
5288
5289 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5290 msiobj_release(&view->hdr);
5291
5292 return rc;
5293}
5294
James Hawkins58bb3572006-12-01 13:22:59 -08005295/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
James Hawkinscf8e9e32007-11-05 04:37:44 -05005296static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
James Hawkins58bb3572006-12-01 13:22:59 -08005297{
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005298 LPCWSTR *vector, *temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08005299 LPWSTR p, q;
5300 DWORD sep_len;
5301
5302 static const WCHAR separator[] = {'[','~',']',0};
5303
5304 *numargs = 0;
5305 sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5306
5307 if (!args)
5308 return NULL;
5309
5310 vector = msi_alloc(sizeof(LPWSTR));
5311 if (!vector)
5312 return NULL;
5313
5314 p = args;
5315 do
5316 {
5317 (*numargs)++;
5318 vector[*numargs - 1] = p;
5319
5320 if ((q = strstrW(p, separator)))
5321 {
5322 *q = '\0';
5323
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005324 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5325 if (!temp_vector)
5326 {
5327 msi_free(vector);
James Hawkins58bb3572006-12-01 13:22:59 -08005328 return NULL;
Lionel Debroux99ad76c2007-12-30 19:01:09 +01005329 }
5330 vector = temp_vector;
James Hawkins58bb3572006-12-01 13:22:59 -08005331
5332 p = q + sep_len;
5333 }
5334 } while (q);
5335
5336 return vector;
5337}
5338
James Hawkins58bb3572006-12-01 13:22:59 -08005339static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5340{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005341 MSIPACKAGE *package = param;
James Hawkins58bb3572006-12-01 13:22:59 -08005342 MSICOMPONENT *comp;
Hans Leidekker129161f2010-03-26 12:11:21 +01005343 MSIRECORD *uirow;
Hans Leidekkerf7879b42010-02-12 10:33:23 +01005344 SC_HANDLE scm = NULL, service = NULL;
Hans Leidekker87448dc2010-03-02 14:56:01 +01005345 LPCWSTR component, *vector = NULL;
Hans Leidekker129161f2010-03-26 12:11:21 +01005346 LPWSTR name, args, display_name = NULL;
5347 DWORD event, numargs, len;
James Hawkins58bb3572006-12-01 13:22:59 -08005348 UINT r = ERROR_FUNCTION_FAILED;
5349
Hans Leidekker87448dc2010-03-02 14:56:01 +01005350 component = MSI_RecordGetString(rec, 6);
5351 comp = get_loaded_component(package, component);
5352 if (!comp)
James Hawkins58bb3572006-12-01 13:22:59 -08005353 return ERROR_SUCCESS;
5354
Hans Leidekker87448dc2010-03-02 14:56:01 +01005355 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5356 {
5357 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5358 comp->Action = comp->Installed;
5359 return ERROR_SUCCESS;
5360 }
5361 comp->Action = INSTALLSTATE_LOCAL;
5362
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005363 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5364 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
James Hawkins58bb3572006-12-01 13:22:59 -08005365 event = MSI_RecordGetInteger(rec, 3);
James Hawkins58bb3572006-12-01 13:22:59 -08005366
5367 if (!(event & msidbServiceControlEventStart))
Hans Leidekkerf7879b42010-02-12 10:33:23 +01005368 {
5369 r = ERROR_SUCCESS;
5370 goto done;
5371 }
James Hawkins58bb3572006-12-01 13:22:59 -08005372
5373 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5374 if (!scm)
5375 {
5376 ERR("Failed to open the service control manager\n");
5377 goto done;
5378 }
5379
Hans Leidekker129161f2010-03-26 12:11:21 +01005380 len = 0;
5381 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5382 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5383 {
5384 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5385 GetServiceDisplayNameW( scm, name, display_name, &len );
5386 }
5387
James Hawkins58bb3572006-12-01 13:22:59 -08005388 service = OpenServiceW(scm, name, SERVICE_START);
5389 if (!service)
5390 {
Hans Leidekkeraa196382010-01-28 11:06:05 +01005391 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
James Hawkins58bb3572006-12-01 13:22:59 -08005392 goto done;
5393 }
5394
James Hawkinscf8e9e32007-11-05 04:37:44 -05005395 vector = msi_service_args_to_vector(args, &numargs);
James Hawkins58bb3572006-12-01 13:22:59 -08005396
Hans Leidekker246f9302010-02-01 09:55:08 +01005397 if (!StartServiceW(service, numargs, vector) &&
5398 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
James Hawkins58bb3572006-12-01 13:22:59 -08005399 {
Hans Leidekkeraa196382010-01-28 11:06:05 +01005400 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
James Hawkins58bb3572006-12-01 13:22:59 -08005401 goto done;
5402 }
5403
5404 r = ERROR_SUCCESS;
5405
5406done:
Hans Leidekker129161f2010-03-26 12:11:21 +01005407 uirow = MSI_CreateRecord( 2 );
5408 MSI_RecordSetStringW( uirow, 1, display_name );
5409 MSI_RecordSetStringW( uirow, 2, name );
5410 ui_actiondata( package, szStartServices, uirow );
5411 msiobj_release( &uirow->hdr );
5412
James Hawkins58bb3572006-12-01 13:22:59 -08005413 CloseServiceHandle(service);
5414 CloseServiceHandle(scm);
5415
Hans Leidekker7c9cb1e2010-01-28 11:05:34 +01005416 msi_free(name);
James Hawkins58bb3572006-12-01 13:22:59 -08005417 msi_free(args);
5418 msi_free(vector);
Hans Leidekker129161f2010-03-26 12:11:21 +01005419 msi_free(display_name);
James Hawkins58bb3572006-12-01 13:22:59 -08005420 return r;
5421}
5422
5423static UINT ACTION_StartServices( MSIPACKAGE *package )
5424{
5425 UINT rc;
5426 MSIQUERY *view;
5427
5428 static const WCHAR query[] = {
5429 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5430 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5431
5432 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5433 if (rc != ERROR_SUCCESS)
5434 return ERROR_SUCCESS;
5435
5436 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5437 msiobj_release(&view->hdr);
5438
5439 return rc;
5440}
5441
James Hawkinsfb508ff2008-03-24 01:31:07 -05005442static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5443{
5444 DWORD i, needed, count;
5445 ENUM_SERVICE_STATUSW *dependencies;
5446 SERVICE_STATUS ss;
5447 SC_HANDLE depserv;
5448
5449 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5450 0, &needed, &count))
5451 return TRUE;
5452
5453 if (GetLastError() != ERROR_MORE_DATA)
5454 return FALSE;
5455
5456 dependencies = msi_alloc(needed);
5457 if (!dependencies)
5458 return FALSE;
5459
5460 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5461 needed, &needed, &count))
5462 goto error;
5463
5464 for (i = 0; i < count; i++)
5465 {
5466 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5467 SERVICE_STOP | SERVICE_QUERY_STATUS);
5468 if (!depserv)
5469 goto error;
5470
5471 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5472 goto error;
5473 }
5474
5475 return TRUE;
5476
5477error:
5478 msi_free(dependencies);
5479 return FALSE;
5480}
5481
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005482static UINT stop_service( LPCWSTR name )
James Hawkinsfb508ff2008-03-24 01:31:07 -05005483{
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005484 SC_HANDLE scm = NULL, service = NULL;
James Hawkinsfb508ff2008-03-24 01:31:07 -05005485 SERVICE_STATUS status;
5486 SERVICE_STATUS_PROCESS ssp;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005487 DWORD needed;
James Hawkinsfb508ff2008-03-24 01:31:07 -05005488
5489 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5490 if (!scm)
5491 {
5492 WARN("Failed to open the SCM: %d\n", GetLastError());
5493 goto done;
5494 }
5495
5496 service = OpenServiceW(scm, name,
5497 SERVICE_STOP |
5498 SERVICE_QUERY_STATUS |
5499 SERVICE_ENUMERATE_DEPENDENTS);
5500 if (!service)
5501 {
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005502 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
James Hawkinsfb508ff2008-03-24 01:31:07 -05005503 goto done;
5504 }
5505
5506 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5507 sizeof(SERVICE_STATUS_PROCESS), &needed))
5508 {
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005509 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
James Hawkinsfb508ff2008-03-24 01:31:07 -05005510 goto done;
5511 }
5512
5513 if (ssp.dwCurrentState == SERVICE_STOPPED)
5514 goto done;
5515
5516 stop_service_dependents(scm, service);
5517
James Hawkinsddfefc02008-03-24 16:16:58 -05005518 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
James Hawkinsfb508ff2008-03-24 01:31:07 -05005519 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5520
5521done:
5522 CloseServiceHandle(service);
5523 CloseServiceHandle(scm);
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005524
5525 return ERROR_SUCCESS;
5526}
5527
5528static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5529{
5530 MSIPACKAGE *package = param;
5531 MSICOMPONENT *comp;
Hans Leidekker129161f2010-03-26 12:11:21 +01005532 MSIRECORD *uirow;
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005533 LPCWSTR component;
Hans Leidekker129161f2010-03-26 12:11:21 +01005534 LPWSTR name = NULL, display_name = NULL;
5535 DWORD event, len;
5536 SC_HANDLE scm;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005537
5538 event = MSI_RecordGetInteger( rec, 3 );
5539 if (!(event & msidbServiceControlEventStop))
5540 return ERROR_SUCCESS;
5541
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005542 component = MSI_RecordGetString( rec, 6 );
5543 comp = get_loaded_component( package, component );
5544 if (!comp)
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005545 return ERROR_SUCCESS;
5546
Hans Leidekker2d3676d2010-03-02 14:56:26 +01005547 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5548 {
5549 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5550 comp->Action = comp->Installed;
5551 return ERROR_SUCCESS;
5552 }
5553 comp->Action = INSTALLSTATE_ABSENT;
5554
Hans Leidekker129161f2010-03-26 12:11:21 +01005555 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5556 if (!scm)
5557 {
5558 ERR("Failed to open the service control manager\n");
5559 goto done;
5560 }
5561
5562 len = 0;
5563 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5564 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5565 {
5566 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5567 GetServiceDisplayNameW( scm, name, display_name, &len );
5568 }
5569 CloseServiceHandle( scm );
5570
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005571 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5572 stop_service( name );
James Hawkinsfb508ff2008-03-24 01:31:07 -05005573
Hans Leidekker129161f2010-03-26 12:11:21 +01005574done:
5575 uirow = MSI_CreateRecord( 2 );
5576 MSI_RecordSetStringW( uirow, 1, display_name );
5577 MSI_RecordSetStringW( uirow, 2, name );
5578 ui_actiondata( package, szStopServices, uirow );
5579 msiobj_release( &uirow->hdr );
5580
5581 msi_free( name );
5582 msi_free( display_name );
James Hawkinsfb508ff2008-03-24 01:31:07 -05005583 return ERROR_SUCCESS;
5584}
5585
5586static UINT ACTION_StopServices( MSIPACKAGE *package )
5587{
5588 UINT rc;
5589 MSIQUERY *view;
5590
5591 static const WCHAR query[] = {
5592 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5593 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5594
5595 rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5596 if (rc != ERROR_SUCCESS)
5597 return ERROR_SUCCESS;
5598
5599 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5600 msiobj_release(&view->hdr);
5601
5602 return rc;
5603}
5604
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005605static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5606{
5607 MSIPACKAGE *package = param;
5608 MSICOMPONENT *comp;
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005609 MSIRECORD *uirow;
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005610 LPCWSTR component;
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005611 LPWSTR name = NULL, display_name = NULL;
5612 DWORD event, len;
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005613 SC_HANDLE scm = NULL, service = NULL;
5614
5615 event = MSI_RecordGetInteger( rec, 3 );
5616 if (!(event & msidbServiceControlEventDelete))
5617 return ERROR_SUCCESS;
5618
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005619 component = MSI_RecordGetString(rec, 6);
5620 comp = get_loaded_component(package, component);
5621 if (!comp)
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005622 return ERROR_SUCCESS;
5623
Hans Leidekkerc13d84f2010-03-02 14:56:51 +01005624 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5625 {
5626 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5627 comp->Action = comp->Installed;
5628 return ERROR_SUCCESS;
5629 }
5630 comp->Action = INSTALLSTATE_ABSENT;
5631
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005632 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5633 stop_service( name );
5634
5635 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5636 if (!scm)
5637 {
5638 WARN("Failed to open the SCM: %d\n", GetLastError());
5639 goto done;
5640 }
5641
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005642 len = 0;
5643 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5644 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5645 {
5646 if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5647 GetServiceDisplayNameW( scm, name, display_name, &len );
5648 }
5649
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005650 service = OpenServiceW( scm, name, DELETE );
5651 if (!service)
5652 {
5653 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5654 goto done;
5655 }
5656
5657 if (!DeleteService( service ))
5658 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5659
5660done:
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005661 uirow = MSI_CreateRecord( 2 );
5662 MSI_RecordSetStringW( uirow, 1, display_name );
5663 MSI_RecordSetStringW( uirow, 2, name );
5664 ui_actiondata( package, szDeleteServices, uirow );
5665 msiobj_release( &uirow->hdr );
5666
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005667 CloseServiceHandle( service );
5668 CloseServiceHandle( scm );
5669 msi_free( name );
Hans Leidekker3c36d9d2010-03-05 12:24:41 +01005670 msi_free( display_name );
Hans Leidekkerb9da31f2010-02-04 10:04:09 +01005671
5672 return ERROR_SUCCESS;
5673}
5674
5675static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5676{
5677 UINT rc;
5678 MSIQUERY *view;
5679
5680 static const WCHAR query[] = {
5681 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5682 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5683
5684 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5685 if (rc != ERROR_SUCCESS)
5686 return ERROR_SUCCESS;
5687
5688 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5689 msiobj_release( &view->hdr );
5690
5691 return rc;
5692}
5693
James Hawkinsd3bec322006-11-27 18:20:33 -08005694static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename )
5695{
5696 MSIFILE *file;
5697
5698 LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry)
5699 {
5700 if (!lstrcmpW(file->File, filename))
5701 return file;
5702 }
5703
5704 return NULL;
5705}
5706
5707static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5708{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005709 MSIPACKAGE *package = param;
James Hawkinsd3bec322006-11-27 18:20:33 -08005710 LPWSTR driver, driver_path, ptr;
5711 WCHAR outpath[MAX_PATH];
5712 MSIFILE *driver_file, *setup_file;
Hans Leidekkereff05032010-03-05 12:25:55 +01005713 MSIRECORD *uirow;
James Hawkinsd3bec322006-11-27 18:20:33 -08005714 LPCWSTR desc;
5715 DWORD len, usage;
5716 UINT r = ERROR_SUCCESS;
5717
5718 static const WCHAR driver_fmt[] = {
5719 'D','r','i','v','e','r','=','%','s',0};
5720 static const WCHAR setup_fmt[] = {
5721 'S','e','t','u','p','=','%','s',0};
5722 static const WCHAR usage_fmt[] = {
5723 'F','i','l','e','U','s','a','g','e','=','1',0};
5724
5725 desc = MSI_RecordGetString(rec, 3);
5726
5727 driver_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5728 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5729
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005730 if (!driver_file)
James Hawkinsd3bec322006-11-27 18:20:33 -08005731 {
5732 ERR("ODBC Driver entry not found!\n");
5733 return ERROR_FUNCTION_FAILED;
5734 }
5735
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005736 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5737 if (setup_file)
5738 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
Hans Leidekker587e1072010-02-22 12:26:09 +01005739 len += lstrlenW(usage_fmt) + 2; /* \0\0 */
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005740
James Hawkinsd3bec322006-11-27 18:20:33 -08005741 driver = msi_alloc(len * sizeof(WCHAR));
5742 if (!driver)
5743 return ERROR_OUTOFMEMORY;
5744
5745 ptr = driver;
5746 lstrcpyW(ptr, desc);
5747 ptr += lstrlenW(ptr) + 1;
5748
Hans Leidekker587e1072010-02-22 12:26:09 +01005749 len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5750 ptr += len + 1;
James Hawkinsd3bec322006-11-27 18:20:33 -08005751
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005752 if (setup_file)
5753 {
Hans Leidekker587e1072010-02-22 12:26:09 +01005754 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5755 ptr += len + 1;
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005756 }
James Hawkinsd3bec322006-11-27 18:20:33 -08005757
5758 lstrcpyW(ptr, usage_fmt);
5759 ptr += lstrlenW(ptr) + 1;
5760 *ptr = '\0';
5761
5762 driver_path = strdupW(driver_file->TargetPath);
5763 ptr = strrchrW(driver_path, '\\');
5764 if (ptr) *ptr = '\0';
5765
5766 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5767 NULL, ODBC_INSTALL_COMPLETE, &usage))
5768 {
5769 ERR("Failed to install SQL driver!\n");
5770 r = ERROR_FUNCTION_FAILED;
5771 }
5772
Hans Leidekkereff05032010-03-05 12:25:55 +01005773 uirow = MSI_CreateRecord( 5 );
5774 MSI_RecordSetStringW( uirow, 1, desc );
5775 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5776 MSI_RecordSetStringW( uirow, 3, driver_path );
5777 ui_actiondata( package, szInstallODBC, uirow );
5778 msiobj_release( &uirow->hdr );
5779
James Hawkinsd3bec322006-11-27 18:20:33 -08005780 msi_free(driver);
5781 msi_free(driver_path);
5782
5783 return r;
5784}
5785
Hans Leidekker33c025b2007-04-22 11:37:51 +02005786static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
5787{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01005788 MSIPACKAGE *package = param;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005789 LPWSTR translator, translator_path, ptr;
5790 WCHAR outpath[MAX_PATH];
5791 MSIFILE *translator_file, *setup_file;
Hans Leidekkereff05032010-03-05 12:25:55 +01005792 MSIRECORD *uirow;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005793 LPCWSTR desc;
5794 DWORD len, usage;
5795 UINT r = ERROR_SUCCESS;
5796
5797 static const WCHAR translator_fmt[] = {
5798 'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
5799 static const WCHAR setup_fmt[] = {
5800 'S','e','t','u','p','=','%','s',0};
5801
5802 desc = MSI_RecordGetString(rec, 3);
5803
5804 translator_file = msi_find_file(package, MSI_RecordGetString(rec, 4));
5805 setup_file = msi_find_file(package, MSI_RecordGetString(rec, 5));
5806
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005807 if (!translator_file)
Hans Leidekker33c025b2007-04-22 11:37:51 +02005808 {
5809 ERR("ODBC Translator entry not found!\n");
5810 return ERROR_FUNCTION_FAILED;
5811 }
5812
Hans Leidekker587e1072010-02-22 12:26:09 +01005813 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005814 if (setup_file)
5815 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5816
Hans Leidekker33c025b2007-04-22 11:37:51 +02005817 translator = msi_alloc(len * sizeof(WCHAR));
5818 if (!translator)
5819 return ERROR_OUTOFMEMORY;
5820
5821 ptr = translator;
5822 lstrcpyW(ptr, desc);
5823 ptr += lstrlenW(ptr) + 1;
5824
Hans Leidekker587e1072010-02-22 12:26:09 +01005825 len = sprintfW(ptr, translator_fmt, translator_file->FileName);
5826 ptr += len + 1;
Hans Leidekker33c025b2007-04-22 11:37:51 +02005827
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005828 if (setup_file)
5829 {
Hans Leidekker587e1072010-02-22 12:26:09 +01005830 len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5831 ptr += len + 1;
Hans Leidekker4742dfb2010-02-11 13:12:55 +01005832 }
Hans Leidekker33c025b2007-04-22 11:37:51 +02005833 *ptr = '\0';
5834
5835 translator_path = strdupW(translator_file->TargetPath);
5836 ptr = strrchrW(translator_path, '\\');
5837 if (ptr) *ptr = '\0';
5838
5839 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
5840 NULL, ODBC_INSTALL_COMPLETE, &usage))
5841 {
5842 ERR("Failed to install SQL translator!\n");
5843 r = ERROR_FUNCTION_FAILED;
5844 }
5845
Hans Leidekkereff05032010-03-05 12:25:55 +01005846 uirow = MSI_CreateRecord( 5 );
5847 MSI_RecordSetStringW( uirow, 1, desc );
5848 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5849 MSI_RecordSetStringW( uirow, 3, translator_path );
5850 ui_actiondata( package, szInstallODBC, uirow );
5851 msiobj_release( &uirow->hdr );
5852
Hans Leidekker33c025b2007-04-22 11:37:51 +02005853 msi_free(translator);
5854 msi_free(translator_path);
5855
5856 return r;
5857}
5858
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005859static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
5860{
Hans Leidekkereff05032010-03-05 12:25:55 +01005861 MSIPACKAGE *package = param;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005862 LPWSTR attrs;
5863 LPCWSTR desc, driver;
5864 WORD request = ODBC_ADD_SYS_DSN;
5865 INT registration;
5866 DWORD len;
5867 UINT r = ERROR_SUCCESS;
Hans Leidekkereff05032010-03-05 12:25:55 +01005868 MSIRECORD *uirow;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005869
5870 static const WCHAR attrs_fmt[] = {
5871 'D','S','N','=','%','s',0 };
5872
5873 desc = MSI_RecordGetString(rec, 3);
5874 driver = MSI_RecordGetString(rec, 4);
5875 registration = MSI_RecordGetInteger(rec, 5);
5876
5877 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
5878 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
5879
Hans Leidekker587e1072010-02-22 12:26:09 +01005880 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005881 attrs = msi_alloc(len * sizeof(WCHAR));
5882 if (!attrs)
5883 return ERROR_OUTOFMEMORY;
5884
Hans Leidekker2568e5e2010-02-11 13:13:19 +01005885 len = sprintfW(attrs, attrs_fmt, desc);
5886 attrs[len + 1] = 0;
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005887
5888 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
5889 {
5890 ERR("Failed to install SQL data source!\n");
5891 r = ERROR_FUNCTION_FAILED;
5892 }
5893
Hans Leidekkereff05032010-03-05 12:25:55 +01005894 uirow = MSI_CreateRecord( 5 );
5895 MSI_RecordSetStringW( uirow, 1, desc );
5896 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5897 MSI_RecordSetInteger( uirow, 3, request );
5898 ui_actiondata( package, szInstallODBC, uirow );
5899 msiobj_release( &uirow->hdr );
5900
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005901 msi_free(attrs);
5902
5903 return r;
5904}
5905
James Hawkinsd3bec322006-11-27 18:20:33 -08005906static UINT ACTION_InstallODBC( MSIPACKAGE *package )
5907{
5908 UINT rc;
5909 MSIQUERY *view;
5910
Hans Leidekker33c025b2007-04-22 11:37:51 +02005911 static const WCHAR driver_query[] = {
James Hawkinsd3bec322006-11-27 18:20:33 -08005912 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5913 'O','D','B','C','D','r','i','v','e','r',0 };
5914
Hans Leidekker33c025b2007-04-22 11:37:51 +02005915 static const WCHAR translator_query[] = {
5916 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5917 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
5918
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005919 static const WCHAR source_query[] = {
5920 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5921 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
5922
Hans Leidekker33c025b2007-04-22 11:37:51 +02005923 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
James Hawkinsd3bec322006-11-27 18:20:33 -08005924 if (rc != ERROR_SUCCESS)
5925 return ERROR_SUCCESS;
5926
5927 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
5928 msiobj_release(&view->hdr);
5929
Hans Leidekker33c025b2007-04-22 11:37:51 +02005930 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
5931 if (rc != ERROR_SUCCESS)
5932 return ERROR_SUCCESS;
5933
5934 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
5935 msiobj_release(&view->hdr);
5936
Hans Leidekker1d19c2b2007-04-22 11:38:02 +02005937 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
5938 if (rc != ERROR_SUCCESS)
5939 return ERROR_SUCCESS;
5940
5941 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
5942 msiobj_release(&view->hdr);
5943
James Hawkinsd3bec322006-11-27 18:20:33 -08005944 return rc;
5945}
5946
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005947static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
5948{
Hans Leidekkera5549302010-03-05 12:26:21 +01005949 MSIPACKAGE *package = param;
5950 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005951 DWORD usage;
5952 LPCWSTR desc;
5953
5954 desc = MSI_RecordGetString( rec, 3 );
5955 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
5956 {
5957 WARN("Failed to remove ODBC driver\n");
5958 }
5959 else if (!usage)
5960 {
5961 FIXME("Usage count reached 0\n");
5962 }
5963
Hans Leidekkera5549302010-03-05 12:26:21 +01005964 uirow = MSI_CreateRecord( 2 );
5965 MSI_RecordSetStringW( uirow, 1, desc );
5966 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5967 ui_actiondata( package, szRemoveODBC, uirow );
5968 msiobj_release( &uirow->hdr );
5969
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005970 return ERROR_SUCCESS;
5971}
5972
5973static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
5974{
Hans Leidekkera5549302010-03-05 12:26:21 +01005975 MSIPACKAGE *package = param;
5976 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005977 DWORD usage;
5978 LPCWSTR desc;
5979
5980 desc = MSI_RecordGetString( rec, 3 );
5981 if (!SQLRemoveTranslatorW( desc, &usage ))
5982 {
5983 WARN("Failed to remove ODBC translator\n");
5984 }
5985 else if (!usage)
5986 {
5987 FIXME("Usage count reached 0\n");
5988 }
5989
Hans Leidekkera5549302010-03-05 12:26:21 +01005990 uirow = MSI_CreateRecord( 2 );
5991 MSI_RecordSetStringW( uirow, 1, desc );
5992 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5993 ui_actiondata( package, szRemoveODBC, uirow );
5994 msiobj_release( &uirow->hdr );
5995
Hans Leidekker28bf8e12010-02-11 13:13:41 +01005996 return ERROR_SUCCESS;
5997}
5998
5999static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6000{
Hans Leidekkera5549302010-03-05 12:26:21 +01006001 MSIPACKAGE *package = param;
6002 MSIRECORD *uirow;
Hans Leidekker28bf8e12010-02-11 13:13:41 +01006003 LPWSTR attrs;
6004 LPCWSTR desc, driver;
6005 WORD request = ODBC_REMOVE_SYS_DSN;
6006 INT registration;
6007 DWORD len;
6008
6009 static const WCHAR attrs_fmt[] = {
6010 'D','S','N','=','%','s',0 };
6011
6012 desc = MSI_RecordGetString( rec, 3 );
6013 driver = MSI_RecordGetString( rec, 4 );
6014 registration = MSI_RecordGetInteger( rec, 5 );
6015
6016 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6017 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6018
Hans Leidekker587e1072010-02-22 12:26:09 +01006019 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
Hans Leidekker28bf8e12010-02-11 13:13:41 +01006020 attrs = msi_alloc( len * sizeof(WCHAR) );
6021 if (!attrs)
6022 return ERROR_OUTOFMEMORY;
6023
6024 FIXME("Use ODBCSourceAttribute table\n");
6025
6026 len = sprintfW( attrs, attrs_fmt, desc );
6027 attrs[len + 1] = 0;
6028
6029 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6030 {
6031 WARN("Failed to remove ODBC data source\n");
6032 }
6033 msi_free( attrs );
6034
Hans Leidekkera5549302010-03-05 12:26:21 +01006035 uirow = MSI_CreateRecord( 3 );
6036 MSI_RecordSetStringW( uirow, 1, desc );
6037 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6038 MSI_RecordSetInteger( uirow, 3, request );
6039 ui_actiondata( package, szRemoveODBC, uirow );
6040 msiobj_release( &uirow->hdr );
6041
Hans Leidekker28bf8e12010-02-11 13:13:41 +01006042 return ERROR_SUCCESS;
6043}
6044
6045static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6046{
6047 UINT rc;
6048 MSIQUERY *view;
6049
6050 static const WCHAR driver_query[] = {
6051 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6052 'O','D','B','C','D','r','i','v','e','r',0 };
6053
6054 static const WCHAR translator_query[] = {
6055 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6056 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6057
6058 static const WCHAR source_query[] = {
6059 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6060 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6061
6062 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6063 if (rc != ERROR_SUCCESS)
6064 return ERROR_SUCCESS;
6065
6066 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6067 msiobj_release( &view->hdr );
6068
6069 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6070 if (rc != ERROR_SUCCESS)
6071 return ERROR_SUCCESS;
6072
6073 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6074 msiobj_release( &view->hdr );
6075
6076 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6077 if (rc != ERROR_SUCCESS)
6078 return ERROR_SUCCESS;
6079
6080 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6081 msiobj_release( &view->hdr );
6082
6083 return rc;
6084}
6085
James Hawkins5b8641a2007-05-30 10:57:31 -07006086#define ENV_ACT_SETALWAYS 0x1
6087#define ENV_ACT_SETABSENT 0x2
6088#define ENV_ACT_REMOVE 0x4
James Hawkins881f5922007-06-13 17:46:09 -07006089#define ENV_ACT_REMOVEMATCH 0x8
James Hawkins5b8641a2007-05-30 10:57:31 -07006090
6091#define ENV_MOD_MACHINE 0x20000000
6092#define ENV_MOD_APPEND 0x40000000
6093#define ENV_MOD_PREFIX 0x80000000
James Hawkins881f5922007-06-13 17:46:09 -07006094#define ENV_MOD_MASK 0xC0000000
6095
6096#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6097
Hans Leidekkerf6221112010-03-03 14:38:06 +01006098static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
James Hawkins881f5922007-06-13 17:46:09 -07006099{
6100 LPCWSTR cptr = *name;
James Hawkins881f5922007-06-13 17:46:09 -07006101
6102 static const WCHAR prefix[] = {'[','~',']',0};
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07006103 static const int prefix_len = 3;
James Hawkins881f5922007-06-13 17:46:09 -07006104
6105 *flags = 0;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006106 while (*cptr)
James Hawkins881f5922007-06-13 17:46:09 -07006107 {
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006108 if (*cptr == '=')
James Hawkins881f5922007-06-13 17:46:09 -07006109 *flags |= ENV_ACT_SETALWAYS;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006110 else if (*cptr == '+')
James Hawkins881f5922007-06-13 17:46:09 -07006111 *flags |= ENV_ACT_SETABSENT;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006112 else if (*cptr == '-')
James Hawkins881f5922007-06-13 17:46:09 -07006113 *flags |= ENV_ACT_REMOVE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006114 else if (*cptr == '!')
James Hawkins881f5922007-06-13 17:46:09 -07006115 *flags |= ENV_ACT_REMOVEMATCH;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006116 else if (*cptr == '*')
James Hawkins881f5922007-06-13 17:46:09 -07006117 *flags |= ENV_MOD_MACHINE;
Dmitry Timoshkov60764852007-06-15 17:43:40 +09006118 else
James Hawkins881f5922007-06-13 17:46:09 -07006119 break;
James Hawkins881f5922007-06-13 17:46:09 -07006120
6121 cptr++;
6122 (*name)++;
6123 }
6124
6125 if (!*cptr)
6126 {
6127 ERR("Missing environment variable\n");
6128 return ERROR_FUNCTION_FAILED;
6129 }
6130
Hans Leidekkere52531a2009-11-13 11:06:12 +01006131 if (*value)
James Hawkins881f5922007-06-13 17:46:09 -07006132 {
Hans Leidekkere52531a2009-11-13 11:06:12 +01006133 LPCWSTR ptr = *value;
6134 if (!strncmpW(ptr, prefix, prefix_len))
James Hawkins881f5922007-06-13 17:46:09 -07006135 {
Jason Edmeades06c45a82010-01-20 09:40:37 +00006136 if (ptr[prefix_len] == szSemiColon[0])
6137 {
6138 *flags |= ENV_MOD_APPEND;
6139 *value += lstrlenW(prefix);
6140 }
6141 else
6142 {
6143 *value = NULL;
6144 }
Hans Leidekkere52531a2009-11-13 11:06:12 +01006145 }
6146 else if (lstrlenW(*value) >= prefix_len)
6147 {
6148 ptr += lstrlenW(ptr) - prefix_len;
6149 if (!lstrcmpW(ptr, prefix))
6150 {
Jason Edmeades06c45a82010-01-20 09:40:37 +00006151 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6152 {
6153 *flags |= ENV_MOD_PREFIX;
6154 /* the "[~]" will be removed by deformat_string */;
6155 }
6156 else
6157 {
6158 *value = NULL;
6159 }
Hans Leidekkere52531a2009-11-13 11:06:12 +01006160 }
James Hawkins881f5922007-06-13 17:46:09 -07006161 }
6162 }
6163
Hans Leidekker659768e2009-09-15 20:52:39 +02006164 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
James Hawkins881f5922007-06-13 17:46:09 -07006165 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6166 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6167 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6168 {
6169 ERR("Invalid flags: %08x\n", *flags);
6170 return ERROR_FUNCTION_FAILED;
6171 }
6172
Hans Leidekker659768e2009-09-15 20:52:39 +02006173 if (!*flags)
6174 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6175
James Hawkins881f5922007-06-13 17:46:09 -07006176 return ERROR_SUCCESS;
6177}
James Hawkins5b8641a2007-05-30 10:57:31 -07006178
Hans Leidekkerf6221112010-03-03 14:38:06 +01006179static UINT open_env_key( DWORD flags, HKEY *key )
James Hawkins5b8641a2007-05-30 10:57:31 -07006180{
James Hawkins9d712382007-11-05 04:47:12 -05006181 static const WCHAR user_env[] =
6182 {'E','n','v','i','r','o','n','m','e','n','t',0};
6183 static const WCHAR machine_env[] =
James Hawkins5b8641a2007-05-30 10:57:31 -07006184 {'S','y','s','t','e','m','\\',
6185 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6186 'C','o','n','t','r','o','l','\\',
6187 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6188 'E','n','v','i','r','o','n','m','e','n','t',0};
Hans Leidekkerf6221112010-03-03 14:38:06 +01006189 const WCHAR *env;
6190 HKEY root;
6191 LONG res;
6192
6193 if (flags & ENV_MOD_MACHINE)
6194 {
6195 env = machine_env;
6196 root = HKEY_LOCAL_MACHINE;
6197 }
6198 else
6199 {
6200 env = user_env;
6201 root = HKEY_CURRENT_USER;
6202 }
6203
6204 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6205 if (res != ERROR_SUCCESS)
6206 {
6207 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6208 return ERROR_FUNCTION_FAILED;
6209 }
6210
6211 return ERROR_SUCCESS;
6212}
6213
6214static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6215{
6216 MSIPACKAGE *package = param;
6217 LPCWSTR name, value, component;
6218 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6219 DWORD flags, type, size;
6220 UINT res;
Hans Leidekker353035f2010-03-04 09:17:50 +01006221 HKEY env = NULL;
Hans Leidekkerf6221112010-03-03 14:38:06 +01006222 MSICOMPONENT *comp;
6223 MSIRECORD *uirow;
6224 int action = 0;
James Hawkins5b8641a2007-05-30 10:57:31 -07006225
Hans Leidekkerc8308ef2010-03-02 14:55:31 +01006226 component = MSI_RecordGetString(rec, 4);
6227 comp = get_loaded_component(package, component);
6228 if (!comp)
6229 return ERROR_SUCCESS;
6230
6231 if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6232 {
6233 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6234 comp->Action = comp->Installed;
6235 return ERROR_SUCCESS;
6236 }
6237 comp->Action = INSTALLSTATE_LOCAL;
6238
James Hawkins881f5922007-06-13 17:46:09 -07006239 name = MSI_RecordGetString(rec, 2);
6240 value = MSI_RecordGetString(rec, 3);
James Hawkins5b8641a2007-05-30 10:57:31 -07006241
Hans Leidekker659768e2009-09-15 20:52:39 +02006242 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6243
Hans Leidekkerf6221112010-03-03 14:38:06 +01006244 res = env_parse_flags(&name, &value, &flags);
Jason Edmeades06c45a82010-01-20 09:40:37 +00006245 if (res != ERROR_SUCCESS || !value)
James Hawkins881f5922007-06-13 17:46:09 -07006246 goto done;
6247
Hans Leidekkere52531a2009-11-13 11:06:12 +01006248 if (value && !deformat_string(package, value, &deformatted))
Mikolaj Zalewskid5b620e2007-10-17 18:22:16 -07006249 {
6250 res = ERROR_OUTOFMEMORY;
6251 goto done;
6252 }
6253
James Hawkins881f5922007-06-13 17:46:09 -07006254 value = deformatted;
James Hawkins5b8641a2007-05-30 10:57:31 -07006255
Hans Leidekkerf6221112010-03-03 14:38:06 +01006256 res = open_env_key( flags, &env );
James Hawkins5b8641a2007-05-30 10:57:31 -07006257 if (res != ERROR_SUCCESS)
James Hawkins881f5922007-06-13 17:46:09 -07006258 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07006259
Hans Leidekkerf6221112010-03-03 14:38:06 +01006260 if (flags & ENV_MOD_MACHINE)
6261 action |= 0x20000000;
James Hawkins5b8641a2007-05-30 10:57:31 -07006262
6263 size = 0;
James Hawkins26d541b2009-12-16 19:05:27 -08006264 type = REG_SZ;
James Hawkins881f5922007-06-13 17:46:09 -07006265 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6266 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
James Hawkins31c461e2008-01-05 11:46:09 -06006267 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
James Hawkins881f5922007-06-13 17:46:09 -07006268 goto done;
James Hawkins5b8641a2007-05-30 10:57:31 -07006269
James Hawkins1b7238a2009-12-15 18:19:19 -08006270 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6271 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006272 action = 0x2;
6273
James Hawkins1b7238a2009-12-15 18:19:19 -08006274 /* Nothing to do. */
6275 if (!value)
6276 {
6277 res = ERROR_SUCCESS;
6278 goto done;
6279 }
6280
Jason Edmeades06c45a82010-01-20 09:40:37 +00006281 /* If we are appending but the string was empty, strip ; */
6282 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6283
James Hawkins1b7238a2009-12-15 18:19:19 -08006284 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6285 newval = strdupW(value);
6286 if (!newval)
6287 {
6288 res = ERROR_OUTOFMEMORY;
6289 goto done;
6290 }
6291 }
6292 else
James Hawkins5b8641a2007-05-30 10:57:31 -07006293 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006294 action = 0x1;
6295
Jason Edmeades06c45a82010-01-20 09:40:37 +00006296 /* Contrary to MSDN, +-variable to [~];path works */
6297 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
James Hawkins5b8641a2007-05-30 10:57:31 -07006298 {
6299 res = ERROR_SUCCESS;
6300 goto done;
6301 }
6302
James Hawkins881f5922007-06-13 17:46:09 -07006303 data = msi_alloc(size);
6304 if (!data)
6305 {
6306 RegCloseKey(env);
6307 return ERROR_OUTOFMEMORY;
6308 }
6309
6310 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6311 if (res != ERROR_SUCCESS)
6312 goto done;
6313
6314 if (flags & ENV_ACT_REMOVEMATCH && (!value || !lstrcmpW(data, value)))
6315 {
Hans Leidekkerf6221112010-03-03 14:38:06 +01006316 action = 0x4;
6317 res = RegDeleteValueW(env, name);
6318 if (res != ERROR_SUCCESS)
6319 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
James Hawkins881f5922007-06-13 17:46:09 -07006320 goto done;
6321 }
6322
James Hawkins1b7238a2009-12-15 18:19:19 -08006323 size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6324 if (flags & ENV_MOD_MASK)
6325 {
6326 DWORD mod_size;
6327 int multiplier = 0;
6328 if (flags & ENV_MOD_APPEND) multiplier++;
6329 if (flags & ENV_MOD_PREFIX) multiplier++;
Jason Edmeades06c45a82010-01-20 09:40:37 +00006330 mod_size = lstrlenW(value) * multiplier;
James Hawkins1b7238a2009-12-15 18:19:19 -08006331 size += mod_size * sizeof(WCHAR);
6332 }
6333
6334 newval = msi_alloc(size);
James Hawkins881f5922007-06-13 17:46:09 -07006335 ptr = newval;
6336 if (!newval)
James Hawkins5b8641a2007-05-30 10:57:31 -07006337 {
6338 res = ERROR_OUTOFMEMORY;
6339 goto done;
6340 }
6341
James Hawkins1b7238a2009-12-15 18:19:19 -08006342 if (flags & ENV_MOD_PREFIX)
6343 {
James Hawkins881f5922007-06-13 17:46:09 -07006344 lstrcpyW(newval, value);
Jason Edmeades06c45a82010-01-20 09:40:37 +00006345 ptr = newval + lstrlenW(value);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006346 action |= 0x80000000;
James Hawkins5b8641a2007-05-30 10:57:31 -07006347 }
6348
James Hawkins1b7238a2009-12-15 18:19:19 -08006349 lstrcpyW(ptr, data);
6350
6351 if (flags & ENV_MOD_APPEND)
6352 {
James Hawkins1b7238a2009-12-15 18:19:19 -08006353 lstrcatW(newval, value);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006354 action |= 0x40000000;
James Hawkins1b7238a2009-12-15 18:19:19 -08006355 }
James Hawkins5b8641a2007-05-30 10:57:31 -07006356 }
Marcus Meissnere2f79462009-12-22 09:32:03 +01006357 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6358 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
Hans Leidekkerf6221112010-03-03 14:38:06 +01006359 if (res)
6360 {
6361 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
6362 }
James Hawkins5b8641a2007-05-30 10:57:31 -07006363
6364done:
Hans Leidekkerf6221112010-03-03 14:38:06 +01006365 uirow = MSI_CreateRecord( 3 );
6366 MSI_RecordSetStringW( uirow, 1, name );
6367 MSI_RecordSetStringW( uirow, 2, newval );
6368 MSI_RecordSetInteger( uirow, 3, action );
6369 ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6370 msiobj_release( &uirow->hdr );
6371
Andrew Talbot0e4ccb82007-06-23 17:28:50 +01006372 if (env) RegCloseKey(env);
James Hawkins881f5922007-06-13 17:46:09 -07006373 msi_free(deformatted);
6374 msi_free(data);
6375 msi_free(newval);
James Hawkins5b8641a2007-05-30 10:57:31 -07006376 return res;
6377}
6378
6379static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6380{
6381 UINT rc;
6382 MSIQUERY * view;
6383 static const WCHAR ExecSeqQuery[] =
6384 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6385 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6386 rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6387 if (rc != ERROR_SUCCESS)
6388 return ERROR_SUCCESS;
6389
6390 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6391 msiobj_release(&view->hdr);
6392
6393 return rc;
6394}
6395
Hans Leidekkerf6221112010-03-03 14:38:06 +01006396static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6397{
6398 MSIPACKAGE *package = param;
6399 LPCWSTR name, value, component;
6400 LPWSTR deformatted = NULL;
6401 DWORD flags;
6402 HKEY env;
6403 MSICOMPONENT *comp;
6404 MSIRECORD *uirow;
6405 int action = 0;
6406 LONG res;
6407 UINT r;
6408
6409 component = MSI_RecordGetString( rec, 4 );
6410 comp = get_loaded_component( package, component );
6411 if (!comp)
6412 return ERROR_SUCCESS;
6413
6414 if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6415 {
6416 TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6417 comp->Action = comp->Installed;
6418 return ERROR_SUCCESS;
6419 }
6420 comp->Action = INSTALLSTATE_ABSENT;
6421
6422 name = MSI_RecordGetString( rec, 2 );
6423 value = MSI_RecordGetString( rec, 3 );
6424
6425 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6426
6427 r = env_parse_flags( &name, &value, &flags );
6428 if (r != ERROR_SUCCESS)
6429 return r;
6430
6431 if (!(flags & ENV_ACT_REMOVE))
6432 {
6433 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6434 return ERROR_SUCCESS;
6435 }
6436
6437 if (value && !deformat_string( package, value, &deformatted ))
6438 return ERROR_OUTOFMEMORY;
6439
6440 value = deformatted;
6441
6442 r = open_env_key( flags, &env );
6443 if (r != ERROR_SUCCESS)
6444 {
6445 r = ERROR_SUCCESS;
6446 goto done;
6447 }
6448
6449 if (flags & ENV_MOD_MACHINE)
6450 action |= 0x20000000;
6451
6452 TRACE("Removing %s\n", debugstr_w(name));
6453
6454 res = RegDeleteValueW( env, name );
6455 if (res != ERROR_SUCCESS)
6456 {
6457 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6458 r = ERROR_SUCCESS;
6459 }
6460
6461done:
6462 uirow = MSI_CreateRecord( 3 );
6463 MSI_RecordSetStringW( uirow, 1, name );
6464 MSI_RecordSetStringW( uirow, 2, value );
6465 MSI_RecordSetInteger( uirow, 3, action );
6466 ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6467 msiobj_release( &uirow->hdr );
6468
6469 if (env) RegCloseKey( env );
6470 msi_free( deformatted );
6471 return r;
6472}
6473
6474static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6475{
6476 UINT rc;
6477 MSIQUERY *view;
6478 static const WCHAR query[] =
6479 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6480 '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6481
6482 rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6483 if (rc != ERROR_SUCCESS)
6484 return ERROR_SUCCESS;
6485
6486 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6487 msiobj_release( &view->hdr );
6488
6489 return rc;
6490}
6491
James Hawkins74239fc2008-08-18 22:59:44 -05006492typedef struct tagMSIASSEMBLY
6493{
6494 struct list entry;
6495 MSICOMPONENT *component;
6496 MSIFEATURE *feature;
6497 MSIFILE *file;
6498 LPWSTR manifest;
6499 LPWSTR application;
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006500 LPWSTR display_name;
James Hawkins74239fc2008-08-18 22:59:44 -05006501 DWORD attributes;
6502 BOOL installed;
6503} MSIASSEMBLY;
6504
James Hawkinsbfe07d12008-04-30 04:22:46 -05006505static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache,
6506 DWORD dwReserved);
6507static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
6508 LPVOID pvReserved, HMODULE *phModDll);
6509
6510static BOOL init_functionpointers(void)
6511{
6512 HRESULT hr;
6513 HMODULE hfusion;
6514 HMODULE hmscoree;
6515
6516 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
6517
6518 hmscoree = LoadLibraryA("mscoree.dll");
6519 if (!hmscoree)
6520 {
6521 WARN("mscoree.dll not available\n");
6522 return FALSE;
6523 }
6524
6525 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
6526 if (!pLoadLibraryShim)
6527 {
6528 WARN("LoadLibraryShim not available\n");
6529 FreeLibrary(hmscoree);
6530 return FALSE;
6531 }
6532
6533 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
6534 if (FAILED(hr))
6535 {
6536 WARN("fusion.dll not available\n");
6537 FreeLibrary(hmscoree);
6538 return FALSE;
6539 }
6540
6541 pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache");
6542
6543 FreeLibrary(hmscoree);
6544 return TRUE;
6545}
6546
James Hawkinsd596ae22008-08-25 00:07:18 -05006547static UINT install_assembly(MSIPACKAGE *package, MSIASSEMBLY *assembly,
6548 LPWSTR path)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006549{
6550 IAssemblyCache *cache;
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006551 MSIRECORD *uirow;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006552 HRESULT hr;
6553 UINT r = ERROR_FUNCTION_FAILED;
6554
James Hawkins74239fc2008-08-18 22:59:44 -05006555 TRACE("installing assembly: %s\n", debugstr_w(path));
6556
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006557 uirow = MSI_CreateRecord( 2 );
6558 MSI_RecordSetStringW( uirow, 2, assembly->display_name );
6559 ui_actiondata( package, szMsiPublishAssemblies, uirow );
6560 msiobj_release( &uirow->hdr );
6561
James Hawkins74239fc2008-08-18 22:59:44 -05006562 if (assembly->feature)
James Hawkinsd596ae22008-08-25 00:07:18 -05006563 msi_feature_set_state(package, assembly->feature, INSTALLSTATE_LOCAL);
James Hawkins74239fc2008-08-18 22:59:44 -05006564
6565 if (assembly->manifest)
6566 FIXME("Manifest unhandled\n");
6567
6568 if (assembly->application)
6569 {
6570 FIXME("Assembly should be privately installed\n");
6571 return ERROR_SUCCESS;
6572 }
6573
6574 if (assembly->attributes == msidbAssemblyAttributesWin32)
6575 {
6576 FIXME("Win32 assemblies not handled\n");
6577 return ERROR_SUCCESS;
6578 }
6579
James Hawkinsbfe07d12008-04-30 04:22:46 -05006580 hr = pCreateAssemblyCache(&cache, 0);
6581 if (FAILED(hr))
6582 goto done;
6583
6584 hr = IAssemblyCache_InstallAssembly(cache, 0, path, NULL);
6585 if (FAILED(hr))
6586 ERR("Failed to install assembly: %s %08x\n", debugstr_w(path), hr);
6587
6588 r = ERROR_SUCCESS;
6589
6590done:
6591 IAssemblyCache_Release(cache);
6592 return r;
6593}
6594
James Hawkins74239fc2008-08-18 22:59:44 -05006595typedef struct tagASSEMBLY_LIST
James Hawkinsbfe07d12008-04-30 04:22:46 -05006596{
James Hawkins74239fc2008-08-18 22:59:44 -05006597 MSIPACKAGE *package;
James Hawkins019f4af2008-10-29 03:18:14 -05006598 IAssemblyCache *cache;
James Hawkins74239fc2008-08-18 22:59:44 -05006599 struct list *assemblies;
6600} ASSEMBLY_LIST;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006601
James Hawkins019f4af2008-10-29 03:18:14 -05006602typedef struct tagASSEMBLY_NAME
6603{
6604 LPWSTR name;
6605 LPWSTR version;
6606 LPWSTR culture;
6607 LPWSTR pubkeytoken;
6608} ASSEMBLY_NAME;
6609
6610static UINT parse_assembly_name(MSIRECORD *rec, LPVOID param)
6611{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006612 ASSEMBLY_NAME *asmname = param;
James Hawkins019f4af2008-10-29 03:18:14 -05006613 LPCWSTR name = MSI_RecordGetString(rec, 2);
6614 LPWSTR val = msi_dup_record_field(rec, 3);
6615
6616 static const WCHAR Name[] = {'N','a','m','e',0};
6617 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
6618 static const WCHAR Culture[] = {'C','u','l','t','u','r','e',0};
6619 static const WCHAR PublicKeyToken[] = {
6620 'P','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
6621
Hans Leidekker43094e42009-02-19 14:05:25 +01006622 if (!strcmpiW(name, Name))
James Hawkins019f4af2008-10-29 03:18:14 -05006623 asmname->name = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006624 else if (!strcmpiW(name, Version))
James Hawkins019f4af2008-10-29 03:18:14 -05006625 asmname->version = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006626 else if (!strcmpiW(name, Culture))
James Hawkins019f4af2008-10-29 03:18:14 -05006627 asmname->culture = val;
Hans Leidekker43094e42009-02-19 14:05:25 +01006628 else if (!strcmpiW(name, PublicKeyToken))
James Hawkins019f4af2008-10-29 03:18:14 -05006629 asmname->pubkeytoken = val;
6630 else
6631 msi_free(val);
6632
6633 return ERROR_SUCCESS;
6634}
6635
6636static void append_str(LPWSTR *str, DWORD *size, LPCWSTR append)
6637{
6638 if (!*str)
6639 {
6640 *size = lstrlenW(append) + 1;
6641 *str = msi_alloc((*size) * sizeof(WCHAR));
6642 lstrcpyW(*str, append);
6643 return;
6644 }
6645
6646 (*size) += lstrlenW(append);
6647 *str = msi_realloc(*str, (*size) * sizeof(WCHAR));
6648 lstrcatW(*str, append);
6649}
6650
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006651static WCHAR *get_assembly_display_name( MSIDATABASE *db, MSICOMPONENT *comp )
James Hawkins019f4af2008-10-29 03:18:14 -05006652{
James Hawkins019f4af2008-10-29 03:18:14 -05006653 static const WCHAR separator[] = {',',' ',0};
6654 static const WCHAR Version[] = {'V','e','r','s','i','o','n','=',0};
6655 static const WCHAR Culture[] = {'C','u','l','t','u','r','e','=',0};
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006656 static const WCHAR PublicKeyToken[] = {'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
James Hawkins019f4af2008-10-29 03:18:14 -05006657 static const WCHAR query[] = {
6658 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6659 '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ',
6660 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`',
6661 '=','\'','%','s','\'',0};
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006662 ASSEMBLY_NAME name;
6663 MSIQUERY *view;
6664 LPWSTR display_name;
6665 DWORD size;
6666 UINT r;
James Hawkins019f4af2008-10-29 03:18:14 -05006667
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006668 display_name = NULL;
6669 memset( &name, 0, sizeof(ASSEMBLY_NAME) );
James Hawkins019f4af2008-10-29 03:18:14 -05006670
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006671 r = MSI_OpenQuery( db, &view, query, comp->Component );
James Hawkins019f4af2008-10-29 03:18:14 -05006672 if (r != ERROR_SUCCESS)
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006673 return NULL;
James Hawkins019f4af2008-10-29 03:18:14 -05006674
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006675 MSI_IterateRecords( view, NULL, parse_assembly_name, &name );
6676 msiobj_release( &view->hdr );
James Hawkins019f4af2008-10-29 03:18:14 -05006677
6678 if (!name.name)
6679 {
6680 ERR("No assembly name specified!\n");
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006681 return NULL;
James Hawkins019f4af2008-10-29 03:18:14 -05006682 }
6683
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006684 append_str( &display_name, &size, name.name );
James Hawkins019f4af2008-10-29 03:18:14 -05006685
6686 if (name.version)
6687 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006688 append_str( &display_name, &size, separator );
6689 append_str( &display_name, &size, Version );
6690 append_str( &display_name, &size, name.version );
James Hawkins019f4af2008-10-29 03:18:14 -05006691 }
James Hawkins019f4af2008-10-29 03:18:14 -05006692 if (name.culture)
6693 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006694 append_str( &display_name, &size, separator );
6695 append_str( &display_name, &size, Culture );
6696 append_str( &display_name, &size, name.culture );
James Hawkins019f4af2008-10-29 03:18:14 -05006697 }
James Hawkins019f4af2008-10-29 03:18:14 -05006698 if (name.pubkeytoken)
6699 {
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006700 append_str( &display_name, &size, separator );
6701 append_str( &display_name, &size, PublicKeyToken );
6702 append_str( &display_name, &size, name.pubkeytoken );
James Hawkins019f4af2008-10-29 03:18:14 -05006703 }
6704
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006705 msi_free( name.name );
6706 msi_free( name.version );
6707 msi_free( name.culture );
6708 msi_free( name.pubkeytoken );
6709
6710 return display_name;
6711}
6712
6713static BOOL check_assembly_installed( MSIDATABASE *db, IAssemblyCache *cache, MSICOMPONENT *comp )
6714{
6715 ASSEMBLY_INFO asminfo;
6716 LPWSTR disp;
6717 BOOL found = FALSE;
6718 HRESULT hr;
6719
6720 disp = get_assembly_display_name( db, comp );
6721 if (!disp)
6722 return FALSE;
6723
6724 memset( &asminfo, 0, sizeof(ASSEMBLY_INFO) );
James Hawkins019f4af2008-10-29 03:18:14 -05006725 asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
James Hawkins019f4af2008-10-29 03:18:14 -05006726
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006727 hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, disp, &asminfo );
6728 if (SUCCEEDED(hr))
6729 found = (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
James Hawkins019f4af2008-10-29 03:18:14 -05006730
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006731 msi_free( disp );
James Hawkins019f4af2008-10-29 03:18:14 -05006732 return found;
6733}
6734
James Hawkins74239fc2008-08-18 22:59:44 -05006735static UINT load_assembly(MSIRECORD *rec, LPVOID param)
6736{
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006737 ASSEMBLY_LIST *list = param;
James Hawkins74239fc2008-08-18 22:59:44 -05006738 MSIASSEMBLY *assembly;
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006739 LPCWSTR component;
James Hawkins74239fc2008-08-18 22:59:44 -05006740
6741 assembly = msi_alloc_zero(sizeof(MSIASSEMBLY));
6742 if (!assembly)
6743 return ERROR_OUTOFMEMORY;
6744
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006745 component = MSI_RecordGetString(rec, 1);
6746 assembly->component = get_loaded_component(list->package, component);
6747 if (!assembly->component)
6748 return ERROR_SUCCESS;
James Hawkins74239fc2008-08-18 22:59:44 -05006749
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006750 if (assembly->component->ActionRequest != INSTALLSTATE_LOCAL &&
6751 assembly->component->ActionRequest != INSTALLSTATE_SOURCE)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006752 {
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006753 TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6754 assembly->component->Action = assembly->component->Installed;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006755 return ERROR_SUCCESS;
6756 }
Hans Leidekker6c6b2a72010-03-02 14:57:37 +01006757 assembly->component->Action = assembly->component->ActionRequest;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006758
James Hawkins74239fc2008-08-18 22:59:44 -05006759 assembly->feature = find_feature_by_name(list->package, MSI_RecordGetString(rec, 2));
6760 assembly->file = msi_find_file(list->package, assembly->component->KeyPath);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006761
James Hawkins74239fc2008-08-18 22:59:44 -05006762 if (!assembly->file)
James Hawkinsbfe07d12008-04-30 04:22:46 -05006763 {
James Hawkins74239fc2008-08-18 22:59:44 -05006764 ERR("File %s not found\n", debugstr_w(assembly->component->KeyPath));
James Hawkins70cd6bf2008-05-20 00:35:42 -05006765 return ERROR_FUNCTION_FAILED;
6766 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05006767
James Hawkins74239fc2008-08-18 22:59:44 -05006768 assembly->manifest = strdupW(MSI_RecordGetString(rec, 3));
6769 assembly->application = strdupW(MSI_RecordGetString(rec, 4));
6770 assembly->attributes = MSI_RecordGetInteger(rec, 5);
Hans Leidekker9c6e6ef2009-03-25 13:52:56 +01006771
6772 if (assembly->application)
6773 {
6774 WCHAR version[24];
6775 DWORD size = sizeof(version)/sizeof(WCHAR);
6776
6777 /* FIXME: we should probably check the manifest file here */
6778
6779 if (!MsiGetFileVersionW(assembly->file->TargetPath, version, &size, NULL, NULL) &&
Hans Leidekker7d837b92009-05-29 15:13:57 +02006780 (!assembly->file->Version || strcmpW(version, assembly->file->Version) >= 0))
Hans Leidekker9c6e6ef2009-03-25 13:52:56 +01006781 {
6782 assembly->installed = TRUE;
6783 }
6784 }
6785 else
6786 assembly->installed = check_assembly_installed(list->package->db,
6787 list->cache,
6788 assembly->component);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006789
James Hawkins74239fc2008-08-18 22:59:44 -05006790 list_add_head(list->assemblies, &assembly->entry);
James Hawkins74239fc2008-08-18 22:59:44 -05006791 return ERROR_SUCCESS;
6792}
James Hawkins9460ae32008-05-13 18:24:48 -05006793
James Hawkins74239fc2008-08-18 22:59:44 -05006794static UINT load_assemblies(MSIPACKAGE *package, struct list *assemblies)
6795{
James Hawkins019f4af2008-10-29 03:18:14 -05006796 IAssemblyCache *cache = NULL;
James Hawkins74239fc2008-08-18 22:59:44 -05006797 ASSEMBLY_LIST list;
James Hawkins019f4af2008-10-29 03:18:14 -05006798 MSIQUERY *view;
6799 HRESULT hr;
James Hawkins74239fc2008-08-18 22:59:44 -05006800 UINT r;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006801
James Hawkins74239fc2008-08-18 22:59:44 -05006802 static const WCHAR query[] =
6803 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6804 '`','M','s','i','A','s','s','e','m','b','l','y','`',0};
6805
6806 r = MSI_DatabaseOpenViewW(package->db, query, &view);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006807 if (r != ERROR_SUCCESS)
James Hawkins74239fc2008-08-18 22:59:44 -05006808 return ERROR_SUCCESS;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006809
James Hawkins019f4af2008-10-29 03:18:14 -05006810 hr = pCreateAssemblyCache(&cache, 0);
6811 if (FAILED(hr))
6812 return ERROR_FUNCTION_FAILED;
6813
James Hawkins74239fc2008-08-18 22:59:44 -05006814 list.package = package;
James Hawkins019f4af2008-10-29 03:18:14 -05006815 list.cache = cache;
James Hawkins74239fc2008-08-18 22:59:44 -05006816 list.assemblies = assemblies;
6817
6818 r = MSI_IterateRecords(view, NULL, load_assembly, &list);
6819 msiobj_release(&view->hdr);
James Hawkinsbfe07d12008-04-30 04:22:46 -05006820
James Hawkins019f4af2008-10-29 03:18:14 -05006821 IAssemblyCache_Release(cache);
6822
James Hawkinsbfe07d12008-04-30 04:22:46 -05006823 return r;
6824}
6825
James Hawkins74239fc2008-08-18 22:59:44 -05006826static void free_assemblies(struct list *assemblies)
6827{
6828 struct list *item, *cursor;
6829
6830 LIST_FOR_EACH_SAFE(item, cursor, assemblies)
6831 {
6832 MSIASSEMBLY *assembly = LIST_ENTRY(item, MSIASSEMBLY, entry);
6833
6834 list_remove(&assembly->entry);
6835 msi_free(assembly->application);
6836 msi_free(assembly->manifest);
Hans Leidekkere90fbf02010-03-05 12:27:31 +01006837 msi_free(assembly->display_name);
James Hawkins74239fc2008-08-18 22:59:44 -05006838 msi_free(assembly);
6839 }
6840}
6841
6842static BOOL find_assembly(struct list *assemblies, LPCWSTR file, MSIASSEMBLY **out)
6843{
6844 MSIASSEMBLY *assembly;
6845
6846 LIST_FOR_EACH_ENTRY(assembly, assemblies, MSIASSEMBLY, entry)
6847 {
6848 if (!lstrcmpW(assembly->file->File, file))
6849 {
6850 *out = assembly;
6851 return TRUE;
6852 }
6853 }
6854
6855 return FALSE;
6856}
6857
6858static BOOL installassembly_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
6859 LPWSTR *path, DWORD *attrs, PVOID user)
6860{
6861 MSIASSEMBLY *assembly;
6862 WCHAR temppath[MAX_PATH];
Michael Stefaniuc5f3ac302009-01-15 09:46:57 +01006863 struct list *assemblies = user;
James Hawkins74239fc2008-08-18 22:59:44 -05006864 UINT r;
6865
6866 if (!find_assembly(assemblies, file, &assembly))
6867 return FALSE;
6868
6869 GetTempPathW(MAX_PATH, temppath);
6870 PathAddBackslashW(temppath);
6871 lstrcatW(temppath, assembly->file->FileName);
6872
6873 if (action == MSICABEXTRACT_BEGINEXTRACT)
6874 {
6875 if (assembly->installed)
6876 return FALSE;
6877
6878 *path = strdupW(temppath);
6879 *attrs = assembly->file->Attributes;
6880 }
6881 else if (action == MSICABEXTRACT_FILEEXTRACTED)
6882 {
6883 assembly->installed = TRUE;
6884
James Hawkinsd596ae22008-08-25 00:07:18 -05006885 r = install_assembly(package, assembly, temppath);
James Hawkins74239fc2008-08-18 22:59:44 -05006886 if (r != ERROR_SUCCESS)
6887 ERR("Failed to install assembly\n");
6888 }
6889
6890 return TRUE;
6891}
6892
James Hawkinsbfe07d12008-04-30 04:22:46 -05006893static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
6894{
James Hawkins74239fc2008-08-18 22:59:44 -05006895 UINT r;
6896 struct list assemblies = LIST_INIT(assemblies);
6897 MSIASSEMBLY *assembly;
6898 MSIMEDIAINFO *mi;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006899
James Hawkins019f4af2008-10-29 03:18:14 -05006900 if (!init_functionpointers() || !pCreateAssemblyCache)
6901 return ERROR_FUNCTION_FAILED;
6902
James Hawkins74239fc2008-08-18 22:59:44 -05006903 r = load_assemblies(package, &assemblies);
6904 if (r != ERROR_SUCCESS)
6905 goto done;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006906
James Hawkins74239fc2008-08-18 22:59:44 -05006907 if (list_empty(&assemblies))
6908 goto done;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006909
James Hawkins74239fc2008-08-18 22:59:44 -05006910 mi = msi_alloc_zero(sizeof(MSIMEDIAINFO));
6911 if (!mi)
6912 {
6913 r = ERROR_OUTOFMEMORY;
6914 goto done;
6915 }
James Hawkinsbfe07d12008-04-30 04:22:46 -05006916
James Hawkins74239fc2008-08-18 22:59:44 -05006917 LIST_FOR_EACH_ENTRY(assembly, &assemblies, MSIASSEMBLY, entry)
6918 {
6919 if (assembly->installed && !mi->is_continuous)
6920 continue;
6921
6922 if (assembly->file->Sequence > mi->last_sequence || mi->is_continuous ||
6923 (assembly->file->IsCompressed && !mi->is_extracted))
6924 {
6925 MSICABDATA data;
6926
6927 r = ready_media(package, assembly->file, mi);
6928 if (r != ERROR_SUCCESS)
6929 {
6930 ERR("Failed to ready media\n");
6931 break;
6932 }
6933
6934 data.mi = mi;
6935 data.package = package;
6936 data.cb = installassembly_cb;
6937 data.user = &assemblies;
6938
6939 if (assembly->file->IsCompressed &&
6940 !msi_cabextract(package, mi, &data))
6941 {
6942 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
6943 r = ERROR_FUNCTION_FAILED;
6944 break;
6945 }
6946 }
6947
6948 if (!assembly->file->IsCompressed)
6949 {
James Hawkinsd15fddf2008-10-06 22:26:20 -05006950 LPWSTR source = resolve_file_source(package, assembly->file);
James Hawkins74239fc2008-08-18 22:59:44 -05006951
James Hawkinsd15fddf2008-10-06 22:26:20 -05006952 r = install_assembly(package, assembly, source);
James Hawkins74239fc2008-08-18 22:59:44 -05006953 if (r != ERROR_SUCCESS)
6954 ERR("Failed to install assembly\n");
James Hawkinsd15fddf2008-10-06 22:26:20 -05006955
6956 msi_free(source);
James Hawkins74239fc2008-08-18 22:59:44 -05006957 }
6958
6959 /* FIXME: write Installer assembly reg values */
6960 }
6961
6962done:
6963 free_assemblies(&assemblies);
6964 return r;
James Hawkinsbfe07d12008-04-30 04:22:46 -05006965}
6966
Hans Leidekker068cb122010-02-10 11:55:59 +01006967static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6968{
6969 LPWSTR key, template, id;
6970 UINT r = ERROR_SUCCESS;
6971
Hans Leidekker186f4ef2010-04-21 11:37:54 +02006972 id = msi_dup_property( package->db, szProductID );
Hans Leidekker068cb122010-02-10 11:55:59 +01006973 if (id)
6974 {
6975 msi_free( id );
6976 return ERROR_SUCCESS;
6977 }
Hans Leidekker186f4ef2010-04-21 11:37:54 +02006978 template = msi_dup_property( package->db, szPIDTemplate );
6979 key = msi_dup_property( package->db, szPIDKEY );
Hans Leidekker068cb122010-02-10 11:55:59 +01006980
6981 if (key && template)
6982 {
6983 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
Hans Leidekkere31ee692010-04-21 11:38:40 +02006984 r = msi_set_property( package->db, szProductID, key );
Hans Leidekker068cb122010-02-10 11:55:59 +01006985 }
6986 msi_free( template );
6987 msi_free( key );
6988 return r;
6989}
6990
Hans Leidekker29f47292010-02-03 09:20:22 +01006991static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6992{
6993 TRACE("\n");
6994 package->need_reboot = 1;
6995 return ERROR_SUCCESS;
6996}
6997
Hans Leidekker5df62d02010-02-10 11:54:57 +01006998static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6999{
Hans Leidekkera64372c2010-03-02 14:55:06 +01007000 static const WCHAR szAvailableFreeReg[] =
7001 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
Hans Leidekker31d06642010-03-05 12:23:22 +01007002 MSIRECORD *uirow;
Hans Leidekker186f4ef2010-04-21 11:37:54 +02007003 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
Hans Leidekkera64372c2010-03-02 14:55:06 +01007004
Hans Leidekker31d06642010-03-05 12:23:22 +01007005 TRACE("%p %d kilobytes\n", package, space);
7006
7007 uirow = MSI_CreateRecord( 1 );
7008 MSI_RecordSetInteger( uirow, 1, space );
7009 ui_actiondata( package, szAllocateRegistrySpace, uirow );
7010 msiobj_release( &uirow->hdr );
7011
Hans Leidekker5df62d02010-02-10 11:54:57 +01007012 return ERROR_SUCCESS;
7013}
7014
7015static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7016{
7017 FIXME("%p\n", package);
7018 return ERROR_SUCCESS;
7019}
7020
7021static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7022{
7023 FIXME("%p\n", package);
7024 return ERROR_SUCCESS;
7025}
7026
Hans Leidekker5a08c9e2010-03-26 12:12:35 +01007027static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7028{
7029 UINT r, count;
7030 MSIQUERY *view;
7031
7032 static const WCHAR driver_query[] = {
7033 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7034 'O','D','B','C','D','r','i','v','e','r',0 };
7035
7036 static const WCHAR translator_query[] = {
7037 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7038 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
7039
7040 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
7041 if (r == ERROR_SUCCESS)
7042 {
7043 count = 0;
7044 r = MSI_IterateRecords( view, &count, NULL, package );
7045 msiobj_release( &view->hdr );
7046 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
7047 }
7048
7049 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
7050 if (r == ERROR_SUCCESS)
7051 {
7052 count = 0;
7053 r = MSI_IterateRecords( view, &count, NULL, package );
7054 msiobj_release( &view->hdr );
7055 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
7056 }
7057
7058 return ERROR_SUCCESS;
7059}
7060
Mike McCormack2586a092005-09-26 09:56:18 +00007061static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
7062 LPCSTR action, LPCWSTR table )
Mike McCormack567f0312005-09-23 11:06:57 +00007063{
7064 static const WCHAR query[] = {
Mike McCormack2586a092005-09-26 09:56:18 +00007065 'S','E','L','E','C','T',' ','*',' ',
7066 'F','R','O','M',' ','`','%','s','`',0 };
Mike McCormack567f0312005-09-23 11:06:57 +00007067 MSIQUERY *view = NULL;
7068 DWORD count = 0;
Mike McCormack2586a092005-09-26 09:56:18 +00007069 UINT r;
Mike McCormack567f0312005-09-23 11:06:57 +00007070
Mike McCormack2586a092005-09-26 09:56:18 +00007071 r = MSI_OpenQuery( package->db, &view, query, table );
7072 if (r == ERROR_SUCCESS)
Mike McCormack567f0312005-09-23 11:06:57 +00007073 {
Mike McCormack2586a092005-09-26 09:56:18 +00007074 r = MSI_IterateRecords(view, &count, NULL, package);
Mike McCormack567f0312005-09-23 11:06:57 +00007075 msiobj_release(&view->hdr);
7076 }
7077
Mike McCormack2586a092005-09-26 09:56:18 +00007078 if (count)
Mike McCormackf1d46462006-10-05 13:41:22 +09007079 FIXME("%s -> %u ignored %s table values\n",
Mike McCormack2586a092005-09-26 09:56:18 +00007080 action, count, debugstr_w(table));
7081
Mike McCormack567f0312005-09-23 11:06:57 +00007082 return ERROR_SUCCESS;
7083}
Mike McCormack94fbe092005-09-23 17:21:10 +00007084
Mike McCormack2586a092005-09-26 09:56:18 +00007085static UINT ACTION_PatchFiles( MSIPACKAGE *package )
7086{
7087 static const WCHAR table[] = { 'P','a','t','c','h',0 };
7088 return msi_unimplemented_action_stub( package, "PatchFiles", table );
7089}
7090
7091static UINT ACTION_BindImage( MSIPACKAGE *package )
7092{
7093 static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
7094 return msi_unimplemented_action_stub( package, "BindImage", table );
7095}
7096
7097static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7098{
7099 static const WCHAR table[] = {
Hans Leidekker930b5e12010-02-26 14:09:29 +01007100 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
Mike McCormack2586a092005-09-26 09:56:18 +00007101 return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7102}
Mike McCormackb9a3a7a2005-09-25 15:14:03 +00007103
Mike McCormack2586a092005-09-26 09:56:18 +00007104static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7105{
7106 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7107 return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
7108}
7109
Mike McCormack3b955152005-09-28 18:10:44 +00007110static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
7111{
7112 static const WCHAR table[] = {
7113 'M','s','i','A','s','s','e','m','b','l','y',0 };
7114 return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
7115}
7116
Mike McCormackf24a9e22005-12-31 13:14:23 +01007117static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7118{
7119 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7120 return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7121}
7122
Mike McCormack88603662006-03-22 23:01:56 +09007123static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7124{
7125 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7126 return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7127}
7128
7129static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7130{
7131 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7132 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7133}
7134
James Hawkins987c2c82007-05-06 20:52:14 -05007135static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7136{
7137 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7138 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7139}
7140
James Hawkins987c2c82007-05-06 20:52:14 -05007141static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7142{
7143 static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
7144 return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
7145}
7146
Hans Leidekker796eed12009-10-15 12:47:48 +02007147typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
7148
7149static const struct
7150{
7151 const WCHAR *action;
7152 UINT (*handler)(MSIPACKAGE *);
7153}
7154StandardActions[] =
7155{
Mike McCormack55942702005-10-30 19:23:28 +00007156 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
Mike McCormack3b955152005-09-28 18:10:44 +00007157 { szAppSearch, ACTION_AppSearch },
7158 { szBindImage, ACTION_BindImage },
James Hawkins987c2c82007-05-06 20:52:14 -05007159 { szCCPSearch, ACTION_CCPSearch },
Mike McCormack3b955152005-09-28 18:10:44 +00007160 { szCostFinalize, ACTION_CostFinalize },
7161 { szCostInitialize, ACTION_CostInitialize },
7162 { szCreateFolders, ACTION_CreateFolders },
7163 { szCreateShortcuts, ACTION_CreateShortcuts },
7164 { szDeleteServices, ACTION_DeleteServices },
Hans Leidekker5df62d02010-02-10 11:54:57 +01007165 { szDisableRollback, ACTION_DisableRollback },
Mike McCormack3b955152005-09-28 18:10:44 +00007166 { szDuplicateFiles, ACTION_DuplicateFiles },
7167 { szExecuteAction, ACTION_ExecuteAction },
7168 { szFileCost, ACTION_FileCost },
7169 { szFindRelatedProducts, ACTION_FindRelatedProducts },
7170 { szForceReboot, ACTION_ForceReboot },
Hans Leidekker5df62d02010-02-10 11:54:57 +01007171 { szInstallAdminPackage, ACTION_InstallAdminPackage },
Mike McCormack3b955152005-09-28 18:10:44 +00007172 { szInstallExecute, ACTION_InstallExecute },
7173 { szInstallExecuteAgain, ACTION_InstallExecute },
7174 { szInstallFiles, ACTION_InstallFiles},
7175 { szInstallFinalize, ACTION_InstallFinalize },
7176 { szInstallInitialize, ACTION_InstallInitialize },
James Hawkins987c2c82007-05-06 20:52:14 -05007177 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
Mike McCormack3b955152005-09-28 18:10:44 +00007178 { szInstallValidate, ACTION_InstallValidate },
7179 { szIsolateComponents, ACTION_IsolateComponents },
7180 { szLaunchConditions, ACTION_LaunchConditions },
7181 { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
7182 { szMoveFiles, ACTION_MoveFiles },
7183 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
7184 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
James Hawkinsd3bec322006-11-27 18:20:33 -08007185 { szInstallODBC, ACTION_InstallODBC },
Mike McCormack3b955152005-09-28 18:10:44 +00007186 { szInstallServices, ACTION_InstallServices },
7187 { szPatchFiles, ACTION_PatchFiles },
7188 { szProcessComponents, ACTION_ProcessComponents },
7189 { szPublishComponents, ACTION_PublishComponents },
7190 { szPublishFeatures, ACTION_PublishFeatures },
7191 { szPublishProduct, ACTION_PublishProduct },
7192 { szRegisterClassInfo, ACTION_RegisterClassInfo },
Mike McCormack88603662006-03-22 23:01:56 +09007193 { szRegisterComPlus, ACTION_RegisterComPlus},
Mike McCormack3b955152005-09-28 18:10:44 +00007194 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
7195 { szRegisterFonts, ACTION_RegisterFonts },
7196 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
7197 { szRegisterProduct, ACTION_RegisterProduct },
7198 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
7199 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
James Hawkins987c2c82007-05-06 20:52:14 -05007200 { szRegisterUser, ACTION_RegisterUser },
7201 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
Mike McCormack3b955152005-09-28 18:10:44 +00007202 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
James Hawkins987c2c82007-05-06 20:52:14 -05007203 { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
7204 { szRemoveFiles, ACTION_RemoveFiles },
7205 { szRemoveFolders, ACTION_RemoveFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00007206 { szRemoveIniValues, ACTION_RemoveIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05007207 { szRemoveODBC, ACTION_RemoveODBC },
7208 { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
7209 { szRemoveShortcuts, ACTION_RemoveShortcuts },
7210 { szResolveSource, ACTION_ResolveSource },
7211 { szRMCCPSearch, ACTION_RMCCPSearch },
Hans Leidekker29f47292010-02-03 09:20:22 +01007212 { szScheduleReboot, ACTION_ScheduleReboot },
Mike McCormack3b955152005-09-28 18:10:44 +00007213 { szSelfRegModules, ACTION_SelfRegModules },
7214 { szSelfUnregModules, ACTION_SelfUnregModules },
Hans Leidekker552a9c92010-02-03 09:19:56 +01007215 { szSetODBCFolders, ACTION_SetODBCFolders },
Mike McCormack3b955152005-09-28 18:10:44 +00007216 { szStartServices, ACTION_StartServices },
7217 { szStopServices, ACTION_StopServices },
James Hawkins987c2c82007-05-06 20:52:14 -05007218 { szUnpublishComponents, ACTION_UnpublishComponents },
7219 { szUnpublishFeatures, ACTION_UnpublishFeatures },
7220 { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
7221 { szUnregisterComPlus, ACTION_UnregisterComPlus },
7222 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
Mike McCormack3b955152005-09-28 18:10:44 +00007223 { szUnregisterFonts, ACTION_UnregisterFonts },
James Hawkins987c2c82007-05-06 20:52:14 -05007224 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
7225 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
7226 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
7227 { szValidateProductID, ACTION_ValidateProductID },
Mike McCormack3b955152005-09-28 18:10:44 +00007228 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
7229 { szWriteIniValues, ACTION_WriteIniValues },
James Hawkins987c2c82007-05-06 20:52:14 -05007230 { szWriteRegistryValues, ACTION_WriteRegistryValues },
7231 { NULL, NULL },
Mike McCormack3b955152005-09-28 18:10:44 +00007232};
Andrew Talbot9e85ec32008-04-03 14:50:28 +01007233
7234static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
7235 UINT* rc, BOOL force )
7236{
7237 BOOL ret = FALSE;
7238 BOOL run = force;
7239 int i;
7240
7241 if (!run && !package->script->CurrentlyScripting)
7242 run = TRUE;
7243
7244 if (!run)
7245 {
7246 if (strcmpW(action,szInstallFinalize) == 0 ||
7247 strcmpW(action,szInstallExecute) == 0 ||
7248 strcmpW(action,szInstallExecuteAgain) == 0)
7249 run = TRUE;
7250 }
7251
7252 i = 0;
7253 while (StandardActions[i].action != NULL)
7254 {
7255 if (strcmpW(StandardActions[i].action, action)==0)
7256 {
7257 if (!run)
7258 {
7259 ui_actioninfo(package, action, TRUE, 0);
7260 *rc = schedule_action(package,INSTALL_SCRIPT,action);
7261 ui_actioninfo(package, action, FALSE, *rc);
7262 }
7263 else
7264 {
7265 ui_actionstart(package, action);
7266 if (StandardActions[i].handler)
7267 {
7268 *rc = StandardActions[i].handler(package);
7269 }
7270 else
7271 {
7272 FIXME("unhandled standard action %s\n",debugstr_w(action));
7273 *rc = ERROR_SUCCESS;
7274 }
7275 }
7276 ret = TRUE;
7277 break;
7278 }
7279 i++;
7280 }
7281 return ret;
7282}
Hans Leidekker796eed12009-10-15 12:47:48 +02007283
7284UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
7285{
7286 UINT rc = ERROR_SUCCESS;
7287 BOOL handled;
7288
7289 TRACE("Performing action (%s)\n", debugstr_w(action));
7290
7291 handled = ACTION_HandleStandardAction(package, action, &rc, force);
7292
7293 if (!handled)
7294 handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
7295
7296 if (!handled)
7297 {
7298 WARN("unhandled msi action %s\n", debugstr_w(action));
7299 rc = ERROR_FUNCTION_NOT_CALLED;
7300 }
7301
7302 return rc;
7303}
7304
7305UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7306{
7307 UINT rc = ERROR_SUCCESS;
7308 BOOL handled = FALSE;
7309
7310 TRACE("Performing action (%s)\n", debugstr_w(action));
7311
7312 handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
7313
7314 if (!handled)
7315 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7316
7317 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7318 handled = TRUE;
7319
7320 if (!handled)
7321 {
7322 WARN("unhandled msi action %s\n", debugstr_w(action));
7323 rc = ERROR_FUNCTION_NOT_CALLED;
7324 }
7325
7326 return rc;
7327}
7328
Hans Leidekkera187b432009-10-15 12:49:10 +02007329static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
Hans Leidekker796eed12009-10-15 12:47:48 +02007330{
7331 UINT rc = ERROR_SUCCESS;
Hans Leidekkera187b432009-10-15 12:49:10 +02007332 MSIRECORD *row;
Hans Leidekker796eed12009-10-15 12:47:48 +02007333
7334 static const WCHAR ExecSeqQuery[] =
7335 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7336 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7337 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7338 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7339 static const WCHAR UISeqQuery[] =
7340 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7341 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7342 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7343 ' ', '=',' ','%','i',0};
7344
Hans Leidekkera187b432009-10-15 12:49:10 +02007345 if (needs_ui_sequence(package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007346 row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7347 else
7348 row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7349
7350 if (row)
7351 {
7352 LPCWSTR action, cond;
7353
7354 TRACE("Running the actions\n");
7355
7356 /* check conditions */
7357 cond = MSI_RecordGetString(row, 2);
7358
7359 /* this is a hack to skip errors in the condition code */
7360 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
Hans Leidekkera187b432009-10-15 12:49:10 +02007361 {
7362 msiobj_release(&row->hdr);
7363 return ERROR_SUCCESS;
7364 }
Hans Leidekker796eed12009-10-15 12:47:48 +02007365
7366 action = MSI_RecordGetString(row, 1);
7367 if (!action)
7368 {
7369 ERR("failed to fetch action\n");
Hans Leidekkera187b432009-10-15 12:49:10 +02007370 msiobj_release(&row->hdr);
7371 return ERROR_FUNCTION_FAILED;
Hans Leidekker796eed12009-10-15 12:47:48 +02007372 }
7373
Hans Leidekkera187b432009-10-15 12:49:10 +02007374 if (needs_ui_sequence(package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007375 rc = ACTION_PerformUIAction(package, action, -1);
7376 else
7377 rc = ACTION_PerformAction(package, action, -1, FALSE);
Hans Leidekkera187b432009-10-15 12:49:10 +02007378
Hans Leidekker796eed12009-10-15 12:47:48 +02007379 msiobj_release(&row->hdr);
7380 }
Hans Leidekker796eed12009-10-15 12:47:48 +02007381
7382 return rc;
7383}
7384
7385/****************************************************
7386 * TOP level entry points
7387 *****************************************************/
7388
7389UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7390 LPCWSTR szCommandLine )
7391{
7392 UINT rc;
Hans Leidekkera187b432009-10-15 12:49:10 +02007393 BOOL ui_exists;
Hans Leidekker796eed12009-10-15 12:47:48 +02007394
7395 static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7396 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7397
Hans Leidekkere31ee692010-04-21 11:38:40 +02007398 msi_set_property( package->db, szAction, szInstall );
Hans Leidekker796eed12009-10-15 12:47:48 +02007399
Hans Leidekker796eed12009-10-15 12:47:48 +02007400 package->script->InWhatSequence = SEQUENCE_INSTALL;
7401
7402 if (szPackagePath)
7403 {
7404 LPWSTR p, dir;
7405 LPCWSTR file;
7406
7407 dir = strdupW(szPackagePath);
7408 p = strrchrW(dir, '\\');
7409 if (p)
7410 {
7411 *(++p) = 0;
7412 file = szPackagePath + (p - dir);
7413 }
7414 else
7415 {
7416 msi_free(dir);
7417 dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7418 GetCurrentDirectoryW(MAX_PATH, dir);
7419 lstrcatW(dir, szBackSlash);
7420 file = szPackagePath;
7421 }
7422
7423 msi_free( package->PackagePath );
7424 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7425 if (!package->PackagePath)
7426 {
7427 msi_free(dir);
7428 return ERROR_OUTOFMEMORY;
7429 }
7430
7431 lstrcpyW(package->PackagePath, dir);
7432 lstrcatW(package->PackagePath, file);
7433 msi_free(dir);
7434
7435 msi_set_sourcedir_props(package, FALSE);
7436 }
7437
7438 msi_parse_command_line( package, szCommandLine, FALSE );
7439
7440 msi_apply_transforms( package );
7441 msi_apply_patches( package );
7442
Hans Leidekker186f4ef2010-04-21 11:37:54 +02007443 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
Hans Leidekker796eed12009-10-15 12:47:48 +02007444 {
7445 TRACE("setting reinstall property\n");
Hans Leidekkere31ee692010-04-21 11:38:40 +02007446 msi_set_property( package->db, szReinstall, szAll );
Hans Leidekker796eed12009-10-15 12:47:48 +02007447 }
7448
7449 /* properties may have been added by a transform */
7450 msi_clone_properties( package );
7451 msi_set_context( package );
7452
Hans Leidekkere3aa2f32009-10-15 12:48:26 +02007453 if (needs_ui_sequence( package))
Hans Leidekker796eed12009-10-15 12:47:48 +02007454 {
7455 package->script->InWhatSequence |= SEQUENCE_UI;
7456 rc = ACTION_ProcessUISequence(package);
Hans Leidekker796eed12009-10-15 12:47:48 +02007457 ui_exists = ui_sequence_exists(package);
7458 if (rc == ERROR_SUCCESS || !ui_exists)
7459 {
7460 package->script->InWhatSequence |= SEQUENCE_EXEC;
7461 rc = ACTION_ProcessExecSequence(package, ui_exists);
7462 }
7463 }
7464 else
7465 rc = ACTION_ProcessExecSequence(package, FALSE);
7466
7467 package->script->CurrentlyScripting = FALSE;
7468
7469 /* process the ending type action */
7470 if (rc == ERROR_SUCCESS)
Hans Leidekkera187b432009-10-15 12:49:10 +02007471 ACTION_PerformActionSequence(package, -1);
Hans Leidekker796eed12009-10-15 12:47:48 +02007472 else if (rc == ERROR_INSTALL_USEREXIT)
Hans Leidekkera187b432009-10-15 12:49:10 +02007473 ACTION_PerformActionSequence(package, -2);
Hans Leidekker796eed12009-10-15 12:47:48 +02007474 else if (rc == ERROR_INSTALL_SUSPEND)
Hans Leidekkera187b432009-10-15 12:49:10 +02007475 ACTION_PerformActionSequence(package, -4);
Hans Leidekker796eed12009-10-15 12:47:48 +02007476 else /* failed */
Hans Leidekkera187b432009-10-15 12:49:10 +02007477 ACTION_PerformActionSequence(package, -3);
Hans Leidekker796eed12009-10-15 12:47:48 +02007478
7479 /* finish up running custom actions */
7480 ACTION_FinishCustomActions(package);
7481
7482 if (rc == ERROR_SUCCESS && package->need_reboot)
7483 return ERROR_SUCCESS_REBOOT_REQUIRED;
7484
7485 return rc;
7486}