2006-02-17 00:04:10 +00:00
|
|
|
/*
|
|
|
|
* Implementation of the Microsoft Installer (msi.dll)
|
|
|
|
*
|
|
|
|
* Copyright 2004,2005 Aric Stewart for CodeWeavers
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2006-08-01 23:12:11 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winerror.h"
|
|
|
|
#include "winreg.h"
|
|
|
|
#include "winsvc.h"
|
|
|
|
#include "odbcinst.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
#include "msidefs.h"
|
|
|
|
#include "winuser.h"
|
|
|
|
#include "shlobj.h"
|
|
|
|
#include "objbase.h"
|
|
|
|
#include "mscoree.h"
|
|
|
|
#include "shlwapi.h"
|
|
|
|
#include "imagehlp.h"
|
|
|
|
#include "wine/unicode.h"
|
|
|
|
#include "winver.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
#include "msipriv.h"
|
|
|
|
#include "resource.h"
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
#define REG_PROGRESS_VALUE 13200
|
|
|
|
#define COMPONENT_PROGRESS_VALUE 24000
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|
|
|
|
|
|
|
static const WCHAR szCreateFolders[] =
|
|
|
|
{'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
|
|
|
|
static const WCHAR szCostFinalize[] =
|
|
|
|
{'C','o','s','t','F','i','n','a','l','i','z','e',0};
|
|
|
|
static const WCHAR szWriteRegistryValues[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szFileCost[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'F','i','l','e','C','o','s','t',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallInitialize[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallValidate[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szLaunchConditions[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szProcessComponents[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szRegisterTypeLibraries[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szCreateShortcuts[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szPublishProduct[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szWriteIniValues[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szSelfRegModules[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szPublishFeatures[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szRegisterProduct[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallExecute[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallExecuteAgain[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallFinalize[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szForceReboot[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'F','o','r','c','e','R','e','b','o','o','t',0};
|
|
|
|
static const WCHAR szResolveSource[] =
|
|
|
|
{'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szAllocateRegistrySpace[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szBindImage[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'B','i','n','d','I','m','a','g','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szDeleteServices[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szDisableRollback[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szExecuteAction[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallAdminPackage[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallSFPCatalogFile[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szIsolateComponents[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
|
2009-10-25 11:06:09 +00:00
|
|
|
static const WCHAR szMigrateFeatureStates[] =
|
|
|
|
{'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallODBC[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','n','s','t','a','l','l','O','D','B','C',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szInstallServices[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szPublishComponents[] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
|
|
|
|
static const WCHAR szRegisterComPlus[] =
|
|
|
|
{'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
|
|
|
|
static const WCHAR szRegisterUser[] =
|
|
|
|
{'R','e','g','i','s','t','e','r','U','s','e','r',0};
|
|
|
|
static const WCHAR szRemoveEnvironmentStrings[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'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};
|
|
|
|
static const WCHAR szRemoveExistingProducts[] =
|
|
|
|
{'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
static const WCHAR szRemoveFolders[] =
|
|
|
|
{'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
|
|
|
|
static const WCHAR szRemoveIniValues[] =
|
|
|
|
{'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
|
|
|
|
static const WCHAR szRemoveODBC[] =
|
|
|
|
{'R','e','m','o','v','e','O','D','B','C',0};
|
|
|
|
static const WCHAR szRemoveRegistryValues[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
static const WCHAR szRemoveShortcuts[] =
|
|
|
|
{'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
|
|
|
|
static const WCHAR szRMCCPSearch[] =
|
|
|
|
{'R','M','C','C','P','S','e','a','r','c','h',0};
|
|
|
|
static const WCHAR szScheduleReboot[] =
|
|
|
|
{'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
|
|
|
|
static const WCHAR szSelfUnregModules[] =
|
|
|
|
{'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
|
|
|
|
static const WCHAR szSetODBCFolders[] =
|
|
|
|
{'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
|
|
|
|
static const WCHAR szStartServices[] =
|
|
|
|
{'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
|
|
|
|
static const WCHAR szStopServices[] =
|
|
|
|
{'S','t','o','p','S','e','r','v','i','c','e','s',0};
|
|
|
|
static const WCHAR szUnpublishComponents[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
static const WCHAR szUnpublishFeatures[] =
|
|
|
|
{'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
|
2016-11-22 12:25:27 +00:00
|
|
|
static const WCHAR szUnpublishProduct[] =
|
|
|
|
{'U','n','p','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
static const WCHAR szUnregisterComPlus[] =
|
|
|
|
{'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
|
|
|
|
static const WCHAR szUnregisterTypeLibraries[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
static const WCHAR szValidateProductID[] =
|
|
|
|
{'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
|
|
|
|
static const WCHAR szWriteEnvironmentStrings[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
|
2018-01-20 11:29:30 +00:00
|
|
|
static const WCHAR szINSTALL[] =
|
|
|
|
{'I','N','S','T','A','L','L',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
struct dummy_thread
|
|
|
|
{
|
|
|
|
HANDLE started;
|
|
|
|
HANDLE stopped;
|
|
|
|
HANDLE thread;
|
|
|
|
};
|
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
static INT ui_actionstart(MSIPACKAGE *package, LPCWSTR action, LPCWSTR description, LPCWSTR template)
|
|
|
|
{
|
|
|
|
WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','A','c','t','i','o','n','T','e','x','t','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
|
|
|
|
MSIRECORD *row, *textrow;
|
|
|
|
INT rc;
|
|
|
|
|
|
|
|
textrow = MSI_QueryGetRecord(package->db, query, action);
|
|
|
|
if (textrow)
|
|
|
|
{
|
|
|
|
description = MSI_RecordGetString(textrow, 2);
|
|
|
|
template = MSI_RecordGetString(textrow, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
row = MSI_CreateRecord(3);
|
|
|
|
if (!row) return -1;
|
|
|
|
MSI_RecordSetStringW(row, 1, action);
|
|
|
|
MSI_RecordSetStringW(row, 2, description);
|
|
|
|
MSI_RecordSetStringW(row, 3, template);
|
|
|
|
rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
|
|
|
|
if (textrow) msiobj_release(&textrow->hdr);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release(&row->hdr);
|
2017-10-08 08:14:40 +00:00
|
|
|
return rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
|
2017-10-08 08:14:40 +00:00
|
|
|
INT rc)
|
|
|
|
{
|
|
|
|
MSIRECORD *row;
|
|
|
|
WCHAR *template;
|
|
|
|
|
|
|
|
template = msi_get_error_message(package->db, start ? MSIERR_INFO_ACTIONSTART : MSIERR_INFO_ACTIONENDED);
|
|
|
|
|
|
|
|
row = MSI_CreateRecord(2);
|
2018-01-20 11:29:30 +00:00
|
|
|
if (!row)
|
|
|
|
{
|
|
|
|
msi_free(template);
|
|
|
|
return;
|
|
|
|
}
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_RecordSetStringW(row, 0, template);
|
|
|
|
MSI_RecordSetStringW(row, 1, action);
|
|
|
|
MSI_RecordSetInteger(row, 2, start ? package->LastActionResult : rc);
|
2006-02-17 00:04:10 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
|
|
|
|
msiobj_release(&row->hdr);
|
2017-10-08 08:14:40 +00:00
|
|
|
msi_free(template);
|
|
|
|
if (!start) package->LastActionResult = rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
enum parse_state
|
|
|
|
{
|
|
|
|
state_whitespace,
|
|
|
|
state_token,
|
|
|
|
state_quote
|
|
|
|
};
|
|
|
|
|
|
|
|
static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
|
|
|
|
{
|
|
|
|
enum parse_state state = state_quote;
|
|
|
|
const WCHAR *p;
|
|
|
|
WCHAR *out = value;
|
2014-04-23 14:48:52 +00:00
|
|
|
BOOL ignore, in_quotes = FALSE;
|
|
|
|
int count = 0, len = 0;
|
2011-03-20 08:47:41 +00:00
|
|
|
|
|
|
|
for (p = str; *p; p++)
|
|
|
|
{
|
2014-04-23 14:48:52 +00:00
|
|
|
ignore = FALSE;
|
2011-03-20 08:47:41 +00:00
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case state_whitespace:
|
|
|
|
switch (*p)
|
|
|
|
{
|
|
|
|
case ' ':
|
2014-04-23 14:48:52 +00:00
|
|
|
in_quotes = TRUE;
|
|
|
|
ignore = TRUE;
|
2012-01-21 17:19:12 +00:00
|
|
|
len++;
|
2011-03-20 08:47:41 +00:00
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
state = state_quote;
|
2012-01-21 17:19:12 +00:00
|
|
|
if (in_quotes && p[1] != '\"') count--;
|
2011-03-20 08:47:41 +00:00
|
|
|
else count++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
state = state_token;
|
2014-04-23 14:48:52 +00:00
|
|
|
in_quotes = TRUE;
|
2011-03-20 08:47:41 +00:00
|
|
|
len++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case state_token:
|
|
|
|
switch (*p)
|
|
|
|
{
|
|
|
|
case '"':
|
|
|
|
state = state_quote;
|
|
|
|
if (in_quotes) count--;
|
|
|
|
else count++;
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
state = state_whitespace;
|
|
|
|
if (!count) goto done;
|
2014-04-23 14:48:52 +00:00
|
|
|
in_quotes = TRUE;
|
2012-01-21 17:19:12 +00:00
|
|
|
len++;
|
2011-03-20 08:47:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
2015-11-21 16:44:38 +00:00
|
|
|
if (count) in_quotes = TRUE;
|
2011-03-20 08:47:41 +00:00
|
|
|
len++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case state_quote:
|
|
|
|
switch (*p)
|
|
|
|
{
|
|
|
|
case '"':
|
2012-01-21 17:19:12 +00:00
|
|
|
if (in_quotes && p[1] != '\"') count--;
|
2011-03-20 08:47:41 +00:00
|
|
|
else count++;
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
state = state_whitespace;
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!count || (count > 1 && !len)) goto done;
|
2014-04-23 14:48:52 +00:00
|
|
|
in_quotes = TRUE;
|
2012-01-21 17:19:12 +00:00
|
|
|
len++;
|
2011-03-20 08:47:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
state = state_token;
|
2015-11-21 16:44:38 +00:00
|
|
|
if (count) in_quotes = TRUE;
|
2011-03-20 08:47:41 +00:00
|
|
|
len++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: break;
|
|
|
|
}
|
2022-03-12 15:57:00 +00:00
|
|
|
if (!ignore && value) *out++ = *p;
|
2015-11-21 16:44:38 +00:00
|
|
|
if (!count) in_quotes = FALSE;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2022-03-12 15:57:00 +00:00
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
if (!len) *value = 0;
|
|
|
|
else *out = 0;
|
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2022-03-12 15:57:00 +00:00
|
|
|
if(quotes) *quotes = count;
|
2011-03-20 08:47:41 +00:00
|
|
|
return p - str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_quotes( WCHAR *str )
|
|
|
|
{
|
|
|
|
WCHAR *p = str;
|
|
|
|
int len = strlenW( str );
|
|
|
|
|
|
|
|
while ((p = strchrW( p, '"' )))
|
|
|
|
{
|
|
|
|
memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
|
|
|
|
BOOL preserve_case )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR ptr, ptr2;
|
2012-01-21 17:19:12 +00:00
|
|
|
int num_quotes;
|
2006-02-17 00:04:10 +00:00
|
|
|
DWORD len;
|
2011-03-20 08:47:41 +00:00
|
|
|
WCHAR *prop, *val;
|
|
|
|
UINT r;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (!szCommandLine)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
ptr = szCommandLine;
|
|
|
|
while (*ptr)
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
while (*ptr == ' ') ptr++;
|
|
|
|
if (!*ptr) break;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
ptr2 = strchrW( ptr, '=' );
|
|
|
|
if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
|
2015-11-21 16:44:38 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
len = ptr2 - ptr;
|
|
|
|
if (!len) return ERROR_INVALID_COMMAND_LINE;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2013-09-22 16:30:18 +00:00
|
|
|
while (ptr[len - 1] == ' ') len--;
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
prop = msi_alloc( (len + 1) * sizeof(WCHAR) );
|
|
|
|
memcpy( prop, ptr, len * sizeof(WCHAR) );
|
|
|
|
prop[len] = 0;
|
|
|
|
if (!preserve_case) struprW( prop );
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
ptr2++;
|
2011-03-20 08:47:41 +00:00
|
|
|
while (*ptr2 == ' ') ptr2++;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
num_quotes = 0;
|
2011-03-20 08:47:41 +00:00
|
|
|
val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) );
|
2012-01-21 17:19:12 +00:00
|
|
|
len = parse_prop( ptr2, val, &num_quotes );
|
|
|
|
if (num_quotes % 2)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
WARN("unbalanced quotes\n");
|
|
|
|
msi_free( val );
|
|
|
|
msi_free( prop );
|
|
|
|
return ERROR_INVALID_COMMAND_LINE;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
remove_quotes( val );
|
|
|
|
TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
r = msi_set_property( package->db, prop, val, -1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir ))
|
2011-03-20 08:47:41 +00:00
|
|
|
msi_reset_folders( package, TRUE );
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
msi_free( val );
|
|
|
|
msi_free( prop );
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
ptr = ptr2 + len;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-03-12 15:57:00 +00:00
|
|
|
const WCHAR *msi_get_command_line_option(const WCHAR *cmd, const WCHAR *option, UINT *len)
|
|
|
|
{
|
|
|
|
DWORD opt_len = strlenW(option);
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (*cmd)
|
|
|
|
{
|
|
|
|
BOOL found = FALSE;
|
|
|
|
|
|
|
|
while (*cmd == ' ') cmd++;
|
|
|
|
if (!*cmd) break;
|
|
|
|
|
|
|
|
if(!strncmpiW(cmd, option, opt_len))
|
|
|
|
found = TRUE;
|
|
|
|
|
|
|
|
cmd = strchrW( cmd, '=' );
|
|
|
|
if(!cmd) break;
|
|
|
|
cmd++;
|
|
|
|
while (*cmd == ' ') cmd++;
|
|
|
|
if (!*cmd) break;
|
|
|
|
|
|
|
|
*len = parse_prop( cmd, NULL, NULL);
|
|
|
|
if (found) return cmd;
|
|
|
|
cmd += *len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-10-22 20:23:59 +00:00
|
|
|
LPCWSTR pc;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPWSTR p, *ret = NULL;
|
|
|
|
UINT count = 0;
|
|
|
|
|
|
|
|
if (!str)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* count the number of substrings */
|
2006-10-22 20:23:59 +00:00
|
|
|
for ( pc = str, count = 0; pc; count++ )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-10-22 20:23:59 +00:00
|
|
|
pc = strchrW( pc, sep );
|
|
|
|
if (pc)
|
|
|
|
pc++;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate space for an array of substring pointers and the substrings */
|
|
|
|
ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
|
|
|
|
(lstrlenW(str)+1) * sizeof(WCHAR) );
|
|
|
|
if (!ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* copy the string and set the pointers */
|
|
|
|
p = (LPWSTR) &ret[count+1];
|
|
|
|
lstrcpyW( p, str );
|
|
|
|
for( count = 0; (ret[count] = p); count++ )
|
|
|
|
{
|
|
|
|
p = strchrW( p, sep );
|
|
|
|
if (p)
|
|
|
|
*p++ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-04-04 13:43:40 +00:00
|
|
|
static BOOL ui_sequence_exists( MSIPACKAGE *package )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query [] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
|
2013-09-22 16:30:18 +00:00
|
|
|
'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
MSIQUERY *view;
|
2013-09-22 16:30:18 +00:00
|
|
|
DWORD count = 0;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2013-09-22 16:30:18 +00:00
|
|
|
if (!(MSI_DatabaseOpenViewW( package->db, query, &view )))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2013-09-22 16:30:18 +00:00
|
|
|
MSI_IterateRecords( view, &count, NULL, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
2013-09-22 16:30:18 +00:00
|
|
|
return count != 0;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2014-04-23 14:48:52 +00:00
|
|
|
WCHAR *source, *check, *p, *db;
|
|
|
|
DWORD len;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2014-04-23 14:48:52 +00:00
|
|
|
if (!(db = msi_dup_property( package->db, szOriginalDatabase )))
|
|
|
|
return ERROR_OUTOFMEMORY;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2014-04-23 14:48:52 +00:00
|
|
|
if (!(p = strrchrW( db, '\\' )) && !(p = strrchrW( db, '/' )))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2014-04-23 14:48:52 +00:00
|
|
|
msi_free(db);
|
|
|
|
return ERROR_SUCCESS;
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
2014-04-23 14:48:52 +00:00
|
|
|
len = p - db + 2;
|
|
|
|
source = msi_alloc( len * sizeof(WCHAR) );
|
|
|
|
lstrcpynW( source, db, len );
|
|
|
|
msi_free( db );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
check = msi_dup_property( package->db, szSourceDir );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!check || replace)
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
UINT r = msi_set_property( package->db, szSourceDir, source, -1 );
|
2010-05-29 08:55:43 +00:00
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
msi_reset_folders( package, TRUE );
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free( check );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
check = msi_dup_property( package->db, szSOURCEDIR );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!check || replace)
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szSOURCEDIR, source, -1 );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
msi_free( check );
|
|
|
|
msi_free( source );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2009-10-25 11:06:09 +00:00
|
|
|
static BOOL needs_ui_sequence(MSIPACKAGE *package)
|
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
|
2009-10-25 11:06:09 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
UINT msi_set_context(MSIPACKAGE *package)
|
2008-07-08 20:52:29 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT r = msi_locate_product( package->ProductCode, &package->Context );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
int num = msi_get_property_int( package->db, szAllUsers, 0 );
|
|
|
|
if (num == 1 || num == 2)
|
|
|
|
package->Context = MSIINSTALLCONTEXT_MACHINE;
|
|
|
|
else
|
|
|
|
package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
|
|
|
|
}
|
2008-07-08 20:52:29 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
|
|
|
UINT rc;
|
|
|
|
LPCWSTR cond, action;
|
2009-10-25 11:06:09 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
action = MSI_RecordGetString(row,1);
|
|
|
|
if (!action)
|
|
|
|
{
|
|
|
|
ERR("Error is retrieving action name\n");
|
2006-11-28 11:21:39 +00:00
|
|
|
return ERROR_FUNCTION_FAILED;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* check conditions */
|
|
|
|
cond = MSI_RecordGetString(row,2);
|
2006-11-28 11:21:39 +00:00
|
|
|
|
|
|
|
/* this is a hack to skip errors in the condition code */
|
2009-10-25 11:06:09 +00:00
|
|
|
if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-11-28 11:21:39 +00:00
|
|
|
TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_PerformAction(package, action);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
msi_dialog_check_messages( NULL );
|
|
|
|
|
|
|
|
if (rc == ERROR_FUNCTION_NOT_CALLED)
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
if (package->need_reboot_now)
|
|
|
|
{
|
|
|
|
TRACE("action %s asked for immediate reboot, suspending installation\n",
|
|
|
|
debugstr_w(action));
|
|
|
|
rc = ACTION_ForceReboot( package );
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
|
|
|
|
' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
|
2006-02-17 00:04:10 +00:00
|
|
|
'>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
|
|
|
|
'`','S','e','q','u','e','n','c','e','`',0};
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("%p %s\n", package, debugstr_w(table));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
r = MSI_OpenQuery( package->db, &view, query, table );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
2009-10-25 11:06:09 +00:00
|
|
|
r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
|
|
|
'`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
|
|
|
|
'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
|
2018-01-20 11:29:30 +00:00
|
|
|
'`','S','e','q','u','e','n','c','e','`',' ', '>',' ','0',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
if (package->ExecuteSequenceRun)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
TRACE("Execute Sequence already Run\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
package->ExecuteSequenceRun = TRUE;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
rc = MSI_OpenQuery(package->db, &view, query);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
TRACE("Running the actions\n");
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szSourceDir, NULL, -1 );
|
2009-10-25 11:06:09 +00:00
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
|
|
|
|
'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
|
|
|
|
'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("Running the actions\n");
|
2009-10-25 11:06:09 +00:00
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
* ACTION helper functions and functions that perform the actions
|
|
|
|
*******************************************************/
|
2022-03-12 15:34:06 +00:00
|
|
|
static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
UINT arc;
|
2017-10-08 08:14:40 +00:00
|
|
|
INT uirc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
uirc = ui_actionstart(package, action, NULL, NULL);
|
|
|
|
if (uirc == IDCANCEL)
|
|
|
|
return ERROR_INSTALL_USEREXIT;
|
|
|
|
ui_actioninfo(package, action, TRUE, 0);
|
2022-03-12 15:34:06 +00:00
|
|
|
arc = ACTION_CustomAction(package, action);
|
2017-10-08 08:14:40 +00:00
|
|
|
uirc = !arc;
|
|
|
|
|
|
|
|
if (arc == ERROR_FUNCTION_NOT_CALLED && needs_ui_sequence(package))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
uirc = ACTION_ShowDialog(package, action);
|
|
|
|
switch (uirc)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
return ERROR_SUCCESS; /* stop immediately */
|
|
|
|
case 0: arc = ERROR_FUNCTION_NOT_CALLED; break;
|
|
|
|
case 1: arc = ERROR_SUCCESS; break;
|
|
|
|
case 2: arc = ERROR_INSTALL_USEREXIT; break;
|
|
|
|
case 3: arc = ERROR_INSTALL_FAILURE; break;
|
|
|
|
case 4: arc = ERROR_INSTALL_SUSPEND; break;
|
|
|
|
case 5: arc = ERROR_MORE_DATA; break;
|
|
|
|
case 6: arc = ERROR_INVALID_HANDLE_STATE; break;
|
|
|
|
case 7: arc = ERROR_INVALID_DATA; break;
|
|
|
|
case 8: arc = ERROR_INSTALL_ALREADY_RUNNING; break;
|
|
|
|
case 9: arc = ERROR_INSTALL_PACKAGE_REJECTED; break;
|
|
|
|
default: arc = ERROR_FUNCTION_FAILED; break;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2017-10-08 08:14:40 +00:00
|
|
|
|
|
|
|
ui_actioninfo(package, action, FALSE, uirc);
|
|
|
|
|
|
|
|
return arc;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
|
|
|
|
{
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
|
|
|
if (!strcmpW( Component, comp->Component )) return comp;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
|
|
|
if (!strcmpW( Feature, feature->Feature )) return feature;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
|
|
|
|
{
|
|
|
|
MSIFILE *file;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
|
|
|
{
|
|
|
|
if (!strcmpW( key, file->File )) return file;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
|
|
|
|
{
|
|
|
|
MSIFOLDER *folder;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
|
|
|
|
{
|
|
|
|
if (!strcmpW( dir, folder->Directory )) return folder;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/*
|
2012-01-21 17:19:12 +00:00
|
|
|
* Recursively create all directories in the path.
|
|
|
|
* shamelessly stolen from setupapi/queue.c
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
2012-01-21 17:19:12 +00:00
|
|
|
BOOL msi_create_full_path( const WCHAR *path )
|
|
|
|
{
|
|
|
|
BOOL ret = TRUE;
|
|
|
|
WCHAR *new_path;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
|
|
|
|
strcpyW( new_path, path );
|
|
|
|
|
|
|
|
while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
|
|
|
|
new_path[len - 1] = 0;
|
|
|
|
|
|
|
|
while (!CreateDirectoryW( new_path, NULL ))
|
|
|
|
{
|
|
|
|
WCHAR *slash;
|
|
|
|
DWORD last_error = GetLastError();
|
|
|
|
if (last_error == ERROR_ALREADY_EXISTS) break;
|
|
|
|
if (last_error != ERROR_PATH_NOT_FOUND)
|
|
|
|
{
|
|
|
|
ret = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!(slash = strrchrW( new_path, '\\' )))
|
|
|
|
{
|
|
|
|
ret = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
len = slash - new_path;
|
|
|
|
new_path[len] = 0;
|
|
|
|
if (!msi_create_full_path( new_path ))
|
|
|
|
{
|
|
|
|
ret = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
new_path[len] = '\\';
|
|
|
|
}
|
|
|
|
msi_free( new_path );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
|
|
|
|
{
|
|
|
|
MSIRECORD *row;
|
|
|
|
|
|
|
|
row = MSI_CreateRecord( 4 );
|
|
|
|
MSI_RecordSetInteger( row, 1, a );
|
|
|
|
MSI_RecordSetInteger( row, 2, b );
|
|
|
|
MSI_RecordSetInteger( row, 3, c );
|
|
|
|
MSI_RecordSetInteger( row, 4, d );
|
|
|
|
MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
|
|
|
|
msiobj_release( &row->hdr );
|
|
|
|
|
|
|
|
msi_dialog_check_messages( NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
|
|
|
|
{
|
|
|
|
if (!comp->Enabled)
|
|
|
|
{
|
|
|
|
TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
|
|
|
|
return INSTALLSTATE_UNKNOWN;
|
|
|
|
}
|
|
|
|
if (package->need_rollback) return comp->Installed;
|
2012-12-09 19:43:59 +00:00
|
|
|
if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
|
|
|
|
{
|
|
|
|
TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
|
|
|
|
return INSTALLSTATE_UNKNOWN;
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
return comp->ActionRequest;
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
|
|
|
|
{
|
|
|
|
if (package->need_rollback) return feature->Installed;
|
|
|
|
return feature->ActionRequest;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2012-01-21 17:19:12 +00:00
|
|
|
LPCWSTR dir, component, full_path;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSIRECORD *uirow;
|
|
|
|
MSIFOLDER *folder;
|
2010-03-01 12:01:30 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString(row, 2);
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!component)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package, component);
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2010-03-01 12:01:30 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
dir = MSI_RecordGetString(row,1);
|
|
|
|
if (!dir)
|
|
|
|
{
|
|
|
|
ERR("Unable to get folder id\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord(1);
|
|
|
|
MSI_RecordSetStringW(uirow, 1, dir);
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
full_path = msi_get_target_folder( package, dir );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!full_path)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("folder is %s\n", debugstr_w(full_path));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
folder = msi_get_loaded_folder( package, dir );
|
|
|
|
if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
|
|
|
|
folder->State = FOLDER_STATE_CREATED;
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_CreateFolders(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szCreateFolders);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
|
|
|
|
msiobj_release(&view->hdr);
|
2010-02-06 21:28:28 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
static void remove_persistent_folder( MSIFOLDER *folder )
|
|
|
|
{
|
|
|
|
FolderList *fl;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
|
|
|
|
{
|
|
|
|
remove_persistent_folder( fl->folder );
|
|
|
|
}
|
|
|
|
if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
|
|
|
|
{
|
|
|
|
if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
2012-01-21 17:19:12 +00:00
|
|
|
LPCWSTR dir, component, full_path;
|
2010-02-06 21:28:28 +00:00
|
|
|
MSIRECORD *uirow;
|
|
|
|
MSIFOLDER *folder;
|
2010-03-01 12:01:30 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString(row, 2);
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!component)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package, component);
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2010-03-01 12:01:30 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-02-06 21:28:28 +00:00
|
|
|
|
|
|
|
dir = MSI_RecordGetString( row, 1 );
|
|
|
|
if (!dir)
|
|
|
|
{
|
|
|
|
ERR("Unable to get folder id\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
full_path = msi_get_target_folder( package, dir );
|
2010-02-06 21:28:28 +00:00
|
|
|
if (!full_path)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Unable to resolve folder %s\n", debugstr_w(dir));
|
2010-02-06 21:28:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
TRACE("folder is %s\n", debugstr_w(full_path));
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 1 );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 1, dir );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-02-06 21:28:28 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
folder = msi_get_loaded_folder( package, dir );
|
2012-05-14 21:41:31 +00:00
|
|
|
remove_persistent_folder( folder );
|
2010-02-06 21:28:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
|
2010-02-06 21:28:28 +00:00
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveFolders);
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
static UINT load_component( MSIRECORD *row, LPVOID param )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
|
|
|
|
if (!comp)
|
2006-08-01 23:12:11 +00:00
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
list_add_tail( &package->components, &comp->entry );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
/* fill in the data */
|
|
|
|
comp->Component = msi_dup_record_field( row, 1 );
|
|
|
|
|
|
|
|
TRACE("Loading Component %s\n", debugstr_w(comp->Component));
|
|
|
|
|
|
|
|
comp->ComponentId = msi_dup_record_field( row, 2 );
|
|
|
|
comp->Directory = msi_dup_record_field( row, 3 );
|
|
|
|
comp->Attributes = MSI_RecordGetInteger(row,4);
|
|
|
|
comp->Condition = msi_dup_record_field( row, 5 );
|
|
|
|
comp->KeyPath = msi_dup_record_field( row, 6 );
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
comp->Installed = INSTALLSTATE_UNKNOWN;
|
2011-03-20 08:47:41 +00:00
|
|
|
comp->Action = INSTALLSTATE_UNKNOWN;
|
|
|
|
comp->ActionRequest = INSTALLSTATE_UNKNOWN;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->assembly = msi_load_assembly( package, comp );
|
2006-08-01 23:12:11 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT msi_load_all_components( MSIPACKAGE *package )
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','o','m','p','o','n','e','n','t','`',0};
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
if (!list_empty(&package->components))
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!msi_init_assembly_caches( package ))
|
|
|
|
{
|
|
|
|
ERR("can't initialize assembly caches\n");
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
r = MSI_IterateRecords(view, NULL, load_component, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return r;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
MSIPACKAGE *package;
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
} _ilfs;
|
|
|
|
|
|
|
|
static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
|
|
|
|
{
|
|
|
|
ComponentList *cl;
|
|
|
|
|
|
|
|
cl = msi_alloc( sizeof (*cl) );
|
|
|
|
if ( !cl )
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
cl->component = comp;
|
|
|
|
list_add_tail( &feature->Components, &cl->entry );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
|
|
|
|
{
|
|
|
|
FeatureList *fl;
|
|
|
|
|
|
|
|
fl = msi_alloc( sizeof(*fl) );
|
|
|
|
if ( !fl )
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
fl->feature = child;
|
|
|
|
list_add_tail( &parent->Children, &fl->entry );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
_ilfs* ilfs = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPCWSTR component;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString(row,1);
|
|
|
|
|
|
|
|
/* check to see if the component is already loaded */
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( ilfs->package, component );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (!comp)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
WARN("ignoring unknown component %s\n", debugstr_w(component));
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
add_feature_component( ilfs->feature, comp );
|
|
|
|
comp->Enabled = TRUE;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT load_feature(MSIRECORD * row, LPVOID param)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`',
|
2006-02-17 00:04:10 +00:00
|
|
|
' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
|
2012-01-21 17:19:12 +00:00
|
|
|
'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ',
|
2006-02-17 00:04:10 +00:00
|
|
|
'`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
_ilfs ilfs;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
/* fill in the data */
|
|
|
|
|
|
|
|
feature = msi_alloc_zero( sizeof (MSIFEATURE) );
|
|
|
|
if (!feature)
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
list_init( &feature->Children );
|
2006-02-17 00:04:10 +00:00
|
|
|
list_init( &feature->Components );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
feature->Feature = msi_dup_record_field( row, 1 );
|
|
|
|
|
|
|
|
TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
|
|
|
|
|
|
|
|
feature->Feature_Parent = msi_dup_record_field( row, 2 );
|
|
|
|
feature->Title = msi_dup_record_field( row, 3 );
|
|
|
|
feature->Description = msi_dup_record_field( row, 4 );
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,5))
|
|
|
|
feature->Display = MSI_RecordGetInteger(row,5);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
feature->Level= MSI_RecordGetInteger(row,6);
|
|
|
|
feature->Directory = msi_dup_record_field( row, 7 );
|
|
|
|
feature->Attributes = MSI_RecordGetInteger(row,8);
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
feature->Installed = INSTALLSTATE_UNKNOWN;
|
2011-03-20 08:47:41 +00:00
|
|
|
feature->Action = INSTALLSTATE_UNKNOWN;
|
|
|
|
feature->ActionRequest = INSTALLSTATE_UNKNOWN;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
list_add_tail( &package->features, &feature->entry );
|
|
|
|
|
|
|
|
/* load feature components */
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_OpenQuery( package->db, &view, query, feature->Feature );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
ilfs.package = package;
|
|
|
|
ilfs.feature = feature;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release(&view->hdr);
|
2012-01-21 17:19:12 +00:00
|
|
|
return rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
static UINT find_feature_children(MSIRECORD * row, LPVOID param)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2006-10-22 20:23:59 +00:00
|
|
|
MSIFEATURE *parent, *child;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
|
2006-10-22 20:23:59 +00:00
|
|
|
if (!child)
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
if (!child->Feature_Parent)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
parent = msi_get_loaded_feature( package, child->Feature_Parent );
|
2006-10-22 20:23:59 +00:00
|
|
|
if (!parent)
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
add_feature_child( parent, child );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT msi_load_all_features( MSIPACKAGE *package )
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ',
|
|
|
|
'`','D','i','s','p','l','a','y','`',0};
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
if (!list_empty(&package->features))
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = MSI_IterateRecords( view, NULL, load_feature, package );
|
2006-10-22 20:23:59 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
msiobj_release( &view->hdr );
|
2006-10-22 20:23:59 +00:00
|
|
|
return r;
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
r = MSI_IterateRecords( view, NULL, find_feature_children, package );
|
2006-08-01 23:12:11 +00:00
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
|
|
|
|
{
|
|
|
|
if (!p)
|
|
|
|
return p;
|
|
|
|
p = strchrW(p, ch);
|
|
|
|
if (!p)
|
|
|
|
return p;
|
|
|
|
*p = 0;
|
|
|
|
return p+1;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
|
|
|
'`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
|
|
|
|
'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
|
|
|
|
MSIQUERY *view = NULL;
|
|
|
|
MSIRECORD *row = NULL;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
TRACE("%s\n", debugstr_w(file->File));
|
|
|
|
|
|
|
|
r = MSI_OpenQuery(package->db, &view, query, file->File);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
r = MSI_ViewExecute(view, NULL);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
r = MSI_ViewFetch(view, &row);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
|
|
|
|
file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
|
|
|
|
file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
|
|
|
|
file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
|
|
|
|
file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (view) msiobj_release(&view->hdr);
|
|
|
|
if (row) msiobj_release(&row->hdr);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
|
|
|
|
{
|
|
|
|
MSIRECORD *row;
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
|
|
|
|
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0};
|
|
|
|
|
|
|
|
row = MSI_QueryGetRecord( package->db, query, file->Sequence );
|
|
|
|
if (!row)
|
|
|
|
{
|
|
|
|
WARN("query failed\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->disk_id = MSI_RecordGetInteger( row, 1 );
|
|
|
|
msiobj_release( &row->hdr );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT load_file(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE* package = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPCWSTR component;
|
|
|
|
MSIFILE *file;
|
|
|
|
|
|
|
|
/* fill in the data */
|
|
|
|
|
|
|
|
file = msi_alloc_zero( sizeof (MSIFILE) );
|
|
|
|
if (!file)
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
file->File = msi_dup_record_field( row, 1 );
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
file->Component = msi_get_loaded_component( package, component );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (!file->Component)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
WARN("Component not found: %s\n", debugstr_w(component));
|
|
|
|
msi_free(file->File);
|
|
|
|
msi_free(file);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
file->FileName = msi_dup_record_field( row, 3 );
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_reduce_to_long_filename( file->FileName );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
file->ShortName = msi_dup_record_field( row, 3 );
|
2006-08-01 23:12:11 +00:00
|
|
|
file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
file->FileSize = MSI_RecordGetInteger( row, 4 );
|
|
|
|
file->Version = msi_dup_record_field( row, 5 );
|
|
|
|
file->Language = msi_dup_record_field( row, 6 );
|
|
|
|
file->Attributes = MSI_RecordGetInteger( row, 7 );
|
|
|
|
file->Sequence = MSI_RecordGetInteger( row, 8 );
|
|
|
|
|
|
|
|
file->state = msifs_invalid;
|
|
|
|
|
2006-08-30 19:24:26 +00:00
|
|
|
/* if the compressed bits are not set in the file attributes,
|
|
|
|
* then read the information from the package word count property
|
|
|
|
*/
|
2008-12-27 15:10:14 +00:00
|
|
|
if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
|
|
|
|
{
|
|
|
|
file->IsCompressed = FALSE;
|
|
|
|
}
|
|
|
|
else if (file->Attributes &
|
|
|
|
(msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
|
2006-08-30 19:24:26 +00:00
|
|
|
{
|
|
|
|
file->IsCompressed = TRUE;
|
|
|
|
}
|
|
|
|
else if (file->Attributes & msidbFileAttributesNoncompressed)
|
|
|
|
{
|
|
|
|
file->IsCompressed = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-21 15:24:30 +00:00
|
|
|
file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
|
2006-08-30 19:24:26 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
load_file_hash(package, file);
|
2010-05-29 08:55:43 +00:00
|
|
|
load_file_disk_id(package, file);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence);
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
list_add_tail( &package->files, &file->entry );
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT load_all_files(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
|
|
|
'`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
|
|
|
|
'`','S','e','q','u','e','n','c','e','`', 0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
if (!list_empty(&package->files))
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, load_file, package);
|
|
|
|
msiobj_release(&view->hdr);
|
2012-01-21 17:19:12 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT load_media( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
UINT disk_id = MSI_RecordGetInteger( row, 1 );
|
|
|
|
const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
/* FIXME: load external cabinets and directory sources too */
|
2015-07-19 23:04:25 +00:00
|
|
|
if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT load_all_media( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`',
|
|
|
|
'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ',
|
|
|
|
'`','D','i','s','k','I','d','`',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
r = MSI_IterateRecords( view, NULL, load_media, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
static UINT load_patch_disk_id( MSIPACKAGE *package, MSIFILEPATCH *patch )
|
|
|
|
{
|
|
|
|
static const WCHAR query[] =
|
|
|
|
{'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
|
|
|
|
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','u',0};
|
|
|
|
MSIRECORD *rec;
|
|
|
|
|
|
|
|
if (!(rec = MSI_QueryGetRecord( package->db, query, patch->Sequence )))
|
|
|
|
{
|
|
|
|
WARN("query failed\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
patch->disk_id = MSI_RecordGetInteger( rec, 1 );
|
|
|
|
msiobj_release( &rec->hdr );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT load_patch(MSIRECORD *row, LPVOID param)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIFILEPATCH *patch;
|
2015-07-19 23:04:25 +00:00
|
|
|
const WCHAR *file_key;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
|
|
|
|
if (!patch)
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
file_key = MSI_RecordGetString( row, 1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
patch->File = msi_get_loaded_file( package, file_key );
|
2015-07-19 23:04:25 +00:00
|
|
|
if (!patch->File)
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
ERR("Failed to find target for patch in File table\n");
|
|
|
|
msi_free(patch);
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
patch->Sequence = MSI_RecordGetInteger( row, 2 );
|
|
|
|
patch->PatchSize = MSI_RecordGetInteger( row, 3 );
|
|
|
|
patch->Attributes = MSI_RecordGetInteger( row, 4 );
|
|
|
|
|
|
|
|
/* FIXME:
|
|
|
|
* Header field - for patch validation.
|
|
|
|
* _StreamRef - External key into MsiPatchHeaders (instead of the header field)
|
|
|
|
*/
|
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
load_patch_disk_id( package, patch );
|
|
|
|
|
|
|
|
TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
|
2012-01-21 17:19:12 +00:00
|
|
|
|
|
|
|
list_add_tail( &package->filepatches, &patch->entry );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT load_all_patches(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ',
|
|
|
|
'`','S','e','q','u','e','n','c','e','`',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
|
|
|
|
|
|
|
if (!list_empty(&package->filepatches))
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, load_patch, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
|
|
|
|
folder->persistent = FALSE;
|
|
|
|
if (!MSI_OpenQuery( package->db, &view, query, folder->Directory ))
|
|
|
|
{
|
|
|
|
if (!MSI_ViewExecute( view, NULL ))
|
|
|
|
{
|
|
|
|
MSIRECORD *rec;
|
|
|
|
if (!MSI_ViewFetch( view, &rec ))
|
|
|
|
{
|
|
|
|
TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
|
|
|
|
folder->persistent = TRUE;
|
|
|
|
msiobj_release( &rec->hdr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT load_folder( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
static WCHAR szEmpty[] = { 0 };
|
|
|
|
LPWSTR p, tgt_short, tgt_long, src_short, src_long;
|
|
|
|
MSIFOLDER *folder;
|
|
|
|
|
|
|
|
if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
list_init( &folder->children );
|
2008-01-16 10:11:22 +00:00
|
|
|
folder->Directory = msi_dup_record_field( row, 1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
folder->Parent = msi_dup_record_field( row, 2 );
|
|
|
|
p = msi_dup_record_field(row, 3);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
TRACE("%s\n", debugstr_w(folder->Directory));
|
|
|
|
|
|
|
|
/* split src and target dir */
|
|
|
|
tgt_short = p;
|
|
|
|
src_short = folder_split_path( p, ':' );
|
|
|
|
|
|
|
|
/* split the long and short paths */
|
|
|
|
tgt_long = folder_split_path( tgt_short, '|' );
|
|
|
|
src_long = folder_split_path( src_short, '|' );
|
|
|
|
|
|
|
|
/* check for no-op dirs */
|
2011-03-20 08:47:41 +00:00
|
|
|
if (tgt_short && !strcmpW( szDot, tgt_short ))
|
2008-01-16 10:11:22 +00:00
|
|
|
tgt_short = szEmpty;
|
2011-03-20 08:47:41 +00:00
|
|
|
if (src_short && !strcmpW( szDot, src_short ))
|
2008-01-16 10:11:22 +00:00
|
|
|
src_short = szEmpty;
|
|
|
|
|
|
|
|
if (!tgt_long)
|
|
|
|
tgt_long = tgt_short;
|
|
|
|
|
|
|
|
if (!src_short) {
|
|
|
|
src_short = tgt_short;
|
|
|
|
src_long = tgt_long;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!src_long)
|
|
|
|
src_long = src_short;
|
|
|
|
|
|
|
|
/* FIXME: use the target short path too */
|
|
|
|
folder->TargetDefault = strdupW(tgt_long);
|
|
|
|
folder->SourceShortPath = strdupW(src_short);
|
|
|
|
folder->SourceLongPath = strdupW(src_long);
|
|
|
|
msi_free(p);
|
|
|
|
|
|
|
|
TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
|
|
|
|
TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
|
|
|
|
TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
load_folder_persistence( package, folder );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
list_add_tail( &package->folders, &folder->entry );
|
2012-01-21 17:19:12 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
|
|
|
|
{
|
|
|
|
FolderList *fl;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
fl->folder = child;
|
|
|
|
list_add_tail( &parent->children, &fl->entry );
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT find_folder_children( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
MSIFOLDER *parent, *child;
|
|
|
|
|
|
|
|
if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
if (!child->Parent) return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (!(parent = msi_get_loaded_folder( package, child->Parent )))
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
return add_folder_child( parent, child );
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT load_all_folders( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','D','i','r','e','c','t','o','r','y','`',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
if (!list_empty(&package->folders))
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
r = MSI_IterateRecords( view, NULL, load_folder, package );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
r = MSI_IterateRecords( view, NULL, find_folder_children, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2008-01-16 10:11:22 +00:00
|
|
|
return r;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
static UINT ACTION_CostInitialize(MSIPACKAGE *package)
|
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szCostingComplete, szZero, -1 );
|
|
|
|
msi_set_property( package->db, szRootDrive, szCRoot, -1 );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
load_all_folders( package );
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_load_all_components( package );
|
|
|
|
msi_load_all_features( package );
|
2006-08-01 23:12:11 +00:00
|
|
|
load_all_files( package );
|
2012-01-21 17:19:12 +00:00
|
|
|
load_all_patches( package );
|
|
|
|
load_all_media( package );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT execute_script( MSIPACKAGE *package, UINT script )
|
|
|
|
{
|
|
|
|
UINT i, rc = ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("executing script %u\n", script);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-12 15:34:06 +00:00
|
|
|
package->script = script;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (script == SCRIPT_ROLLBACK)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
for (i = package->script_actions_count[script]; i > 0; i--)
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_PerformAction(package, package->script_actions[script][i-1]);
|
2018-01-20 11:29:30 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("Execution of script %i halted; action %s returned %u\n",
|
|
|
|
script, debugstr_w(package->script_actions[script][i-1]), rc);
|
|
|
|
break;
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
for (i = 0; i < package->script_actions_count[script]; i++)
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_PerformAction(package, package->script_actions[script][i]);
|
2018-01-20 11:29:30 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("Execution of script %i halted; action %s returned %u\n",
|
|
|
|
script, debugstr_w(package->script_actions[script][i]), rc);
|
|
|
|
break;
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2022-03-12 15:34:06 +00:00
|
|
|
|
|
|
|
package->script = SCRIPT_NONE;
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
msi_free_action_script(package, script);
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_FileCost(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
static void get_client_counts( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
HKEY hkey;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
|
|
|
if (!comp->ComponentId) continue;
|
|
|
|
|
|
|
|
if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) &&
|
|
|
|
MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
|
|
|
|
{
|
|
|
|
comp->num_clients = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
|
|
|
|
NULL, NULL, NULL, NULL );
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
MSICOMPONENT *comp;
|
2008-12-27 15:10:14 +00:00
|
|
|
UINT r;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp->ComponentId) continue;
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
r = MsiQueryComponentStateW( package->ProductCode, NULL,
|
|
|
|
MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
|
|
|
|
&comp->Installed );
|
2012-05-14 21:41:31 +00:00
|
|
|
if (r == ERROR_SUCCESS) continue;
|
|
|
|
|
|
|
|
r = MsiQueryComponentStateW( package->ProductCode, NULL,
|
|
|
|
MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
|
|
|
|
&comp->Installed );
|
|
|
|
if (r == ERROR_SUCCESS) continue;
|
|
|
|
|
|
|
|
r = MsiQueryComponentStateW( package->ProductCode, NULL,
|
|
|
|
MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
|
|
|
|
&comp->Installed );
|
|
|
|
if (r == ERROR_SUCCESS) continue;
|
|
|
|
|
|
|
|
comp->Installed = INSTALLSTATE_ABSENT;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
|
|
|
|
|
|
|
|
if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
|
2008-12-27 15:10:14 +00:00
|
|
|
feature->Installed = INSTALLSTATE_ABSENT;
|
|
|
|
else
|
2011-03-20 08:47:41 +00:00
|
|
|
feature->Installed = state;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
|
|
|
|
{
|
|
|
|
return (feature->Level > 0 && feature->Level <= level);
|
|
|
|
}
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
static BOOL process_state_property(MSIPACKAGE* package, int level,
|
|
|
|
LPCWSTR property, INSTALLSTATE state)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
LPWSTR override;
|
|
|
|
MSIFEATURE *feature;
|
2014-09-23 18:32:48 +00:00
|
|
|
BOOL remove = !strcmpW(property, szRemove);
|
|
|
|
BOOL reinstall = !strcmpW(property, szReinstall);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
override = msi_dup_property( package->db, property );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!override)
|
|
|
|
return FALSE;
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2014-09-23 18:32:48 +00:00
|
|
|
if (feature->Level <= 0)
|
2008-12-27 15:10:14 +00:00
|
|
|
continue;
|
|
|
|
|
2014-09-23 18:32:48 +00:00
|
|
|
if (reinstall)
|
|
|
|
state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : feature->Installed);
|
|
|
|
else if (remove)
|
|
|
|
state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : INSTALLSTATE_ABSENT);
|
2009-05-20 12:59:23 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpiW( override, szAll ))
|
|
|
|
{
|
2014-09-23 18:32:48 +00:00
|
|
|
feature->Action = state;
|
|
|
|
feature->ActionRequest = state;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
LPWSTR ptr = override;
|
|
|
|
LPWSTR ptr2 = strchrW(override,',');
|
|
|
|
|
|
|
|
while (ptr)
|
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
int len = ptr2 - ptr;
|
|
|
|
|
|
|
|
if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len))
|
|
|
|
|| (!ptr2 && !strcmpW(ptr, feature->Feature)))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2014-09-23 18:32:48 +00:00
|
|
|
feature->Action = state;
|
|
|
|
feature->ActionRequest = state;
|
2006-02-17 00:04:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ptr2)
|
|
|
|
{
|
|
|
|
ptr=ptr2+1;
|
|
|
|
ptr2 = strchrW(ptr,',');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(override);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static BOOL process_overrides( MSIPACKAGE *package, int level )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
static const WCHAR szAddLocal[] =
|
|
|
|
{'A','D','D','L','O','C','A','L',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szAddSource[] =
|
|
|
|
{'A','D','D','S','O','U','R','C','E',0};
|
2009-05-20 12:59:23 +00:00
|
|
|
static const WCHAR szAdvertise[] =
|
|
|
|
{'A','D','V','E','R','T','I','S','E',0};
|
2010-02-06 21:28:28 +00:00
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
/* all these activation/deactivation things happen in order and things
|
|
|
|
* later on the list override things earlier on the list.
|
|
|
|
*
|
|
|
|
* 0 INSTALLLEVEL processing
|
|
|
|
* 1 ADDLOCAL
|
|
|
|
* 2 REMOVE
|
|
|
|
* 3 ADDSOURCE
|
|
|
|
* 4 ADDDEFAULT
|
|
|
|
* 5 REINSTALL
|
|
|
|
* 6 ADVERTISE
|
|
|
|
* 7 COMPADDLOCAL
|
|
|
|
* 8 COMPADDSOURCE
|
|
|
|
* 9 FILEADDLOCAL
|
|
|
|
* 10 FILEADDSOURCE
|
|
|
|
* 11 FILEADDDEFAULT
|
|
|
|
*/
|
|
|
|
ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL );
|
|
|
|
ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT );
|
|
|
|
ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE );
|
|
|
|
ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN );
|
|
|
|
ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED );
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
if (ret)
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szPreselected, szOne, -1 );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2017-06-03 22:29:55 +00:00
|
|
|
static void disable_children( MSIFEATURE *feature, int level )
|
|
|
|
{
|
|
|
|
FeatureList *fl;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
|
|
|
|
{
|
|
|
|
if (!is_feature_selected( feature, level ))
|
|
|
|
{
|
|
|
|
TRACE("child %s (level %d request %d) follows disabled parent %s (level %d request %d)\n",
|
|
|
|
debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
|
|
|
|
debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
|
|
|
|
|
|
|
|
fl->feature->Level = feature->Level;
|
|
|
|
fl->feature->Action = INSTALLSTATE_UNKNOWN;
|
|
|
|
fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
|
|
|
|
}
|
|
|
|
disable_children( fl->feature, level );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void follow_parent( MSIFEATURE *feature )
|
|
|
|
{
|
|
|
|
FeatureList *fl;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
|
|
|
|
{
|
|
|
|
if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
|
|
|
|
{
|
|
|
|
TRACE("child %s (level %d request %d) follows parent %s (level %d request %d)\n",
|
|
|
|
debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
|
|
|
|
debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
|
|
|
|
|
|
|
|
fl->feature->Action = feature->Action;
|
|
|
|
fl->feature->ActionRequest = feature->ActionRequest;
|
|
|
|
}
|
|
|
|
follow_parent( fl->feature );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
UINT MSI_SetFeatureStates(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
int level;
|
|
|
|
MSICOMPONENT* component;
|
|
|
|
MSIFEATURE *feature;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
TRACE("Checking Install Level\n");
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
level = msi_get_property_int(package->db, szInstallLevel, 1);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
if (msi_get_property_int( package->db, szPreselected, 0 ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!is_feature_selected( feature, level )) continue;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
if (feature->Installed == INSTALLSTATE_ABSENT)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
feature->Action = INSTALLSTATE_UNKNOWN;
|
|
|
|
feature->ActionRequest = INSTALLSTATE_UNKNOWN;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
feature->Action = feature->Installed;
|
|
|
|
feature->ActionRequest = feature->Installed;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2017-06-03 22:29:55 +00:00
|
|
|
if (feature->Feature_Parent) continue;
|
|
|
|
disable_children( feature, level );
|
|
|
|
follow_parent( feature );
|
2006-10-22 20:23:59 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2018-01-20 11:29:30 +00:00
|
|
|
else if (!msi_get_property_int( package->db, szInstalled, 0 ))
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
{
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!is_feature_selected( feature, level )) continue;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
if (feature->Attributes & msidbFeatureAttributesFavorSource)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
feature->Action = INSTALLSTATE_SOURCE;
|
|
|
|
feature->ActionRequest = INSTALLSTATE_SOURCE;
|
|
|
|
}
|
|
|
|
else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
|
|
|
|
{
|
|
|
|
feature->Action = INSTALLSTATE_ADVERTISED;
|
|
|
|
feature->ActionRequest = INSTALLSTATE_ADVERTISED;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
feature->Action = INSTALLSTATE_LOCAL;
|
|
|
|
feature->ActionRequest = INSTALLSTATE_LOCAL;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-20 11:29:30 +00:00
|
|
|
/* disable child features of unselected parent or follow parent */
|
2012-01-21 17:19:12 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2017-06-03 22:29:55 +00:00
|
|
|
if (feature->Feature_Parent) continue;
|
|
|
|
disable_children( feature, level );
|
|
|
|
follow_parent( feature );
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
/* now we want to set component state based based on feature state */
|
2006-02-17 00:04:10 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
|
|
|
ComponentList *cl;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
debugstr_w(feature->Feature), feature->Level, feature->Installed,
|
|
|
|
feature->ActionRequest, feature->Action);
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* features with components that have compressed files are made local */
|
|
|
|
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (cl->component->ForceLocalState &&
|
2010-10-22 13:18:11 +00:00
|
|
|
feature->ActionRequest == INSTALLSTATE_SOURCE)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
feature->Action = INSTALLSTATE_LOCAL;
|
|
|
|
feature->ActionRequest = INSTALLSTATE_LOCAL;
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
|
|
|
|
{
|
|
|
|
component = cl->component;
|
|
|
|
|
2010-10-22 13:18:11 +00:00
|
|
|
switch (feature->ActionRequest)
|
2006-10-22 20:23:59 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
case INSTALLSTATE_ABSENT:
|
|
|
|
component->anyAbsent = 1;
|
|
|
|
break;
|
|
|
|
case INSTALLSTATE_ADVERTISED:
|
2014-04-23 14:48:52 +00:00
|
|
|
component->hasAdvertisedFeature = 1;
|
2008-01-16 10:11:22 +00:00
|
|
|
break;
|
|
|
|
case INSTALLSTATE_SOURCE:
|
|
|
|
component->hasSourceFeature = 1;
|
|
|
|
break;
|
|
|
|
case INSTALLSTATE_LOCAL:
|
|
|
|
component->hasLocalFeature = 1;
|
|
|
|
break;
|
|
|
|
case INSTALLSTATE_DEFAULT:
|
|
|
|
if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
|
2014-04-23 14:48:52 +00:00
|
|
|
component->hasAdvertisedFeature = 1;
|
2008-01-16 10:11:22 +00:00
|
|
|
else if (feature->Attributes & msidbFeatureAttributesFavorSource)
|
|
|
|
component->hasSourceFeature = 1;
|
2006-11-28 11:21:39 +00:00
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
component->hasLocalFeature = 1;
|
|
|
|
break;
|
2018-01-20 11:29:30 +00:00
|
|
|
case INSTALLSTATE_UNKNOWN:
|
|
|
|
if (feature->Installed == INSTALLSTATE_ADVERTISED)
|
|
|
|
component->hasAdvertisedFeature = 1;
|
|
|
|
if (feature->Installed == INSTALLSTATE_SOURCE)
|
|
|
|
component->hasSourceFeature = 1;
|
|
|
|
if (feature->Installed == INSTALLSTATE_LOCAL)
|
|
|
|
component->hasLocalFeature = 1;
|
|
|
|
break;
|
2008-01-16 10:11:22 +00:00
|
|
|
default:
|
|
|
|
break;
|
2006-10-22 20:23:59 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
|
|
|
/* check if it's local or source */
|
|
|
|
if (!(component->Attributes & msidbComponentAttributesOptional) &&
|
|
|
|
(component->hasLocalFeature || component->hasSourceFeature))
|
|
|
|
{
|
|
|
|
if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
|
|
|
|
!component->ForceLocalState)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
|
|
|
component->Action = INSTALLSTATE_SOURCE;
|
|
|
|
component->ActionRequest = INSTALLSTATE_SOURCE;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
else
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
|
|
|
component->Action = INSTALLSTATE_LOCAL;
|
|
|
|
component->ActionRequest = INSTALLSTATE_LOCAL;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* if any feature is local, the component must be local too */
|
|
|
|
if (component->hasLocalFeature)
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
component->Action = INSTALLSTATE_LOCAL;
|
|
|
|
component->ActionRequest = INSTALLSTATE_LOCAL;
|
2008-01-16 10:11:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (component->hasSourceFeature)
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
component->Action = INSTALLSTATE_SOURCE;
|
|
|
|
component->ActionRequest = INSTALLSTATE_SOURCE;
|
2008-01-16 10:11:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2014-04-23 14:48:52 +00:00
|
|
|
if (component->hasAdvertisedFeature)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
component->Action = INSTALLSTATE_ADVERTISED;
|
|
|
|
component->ActionRequest = INSTALLSTATE_ADVERTISED;
|
2008-01-16 10:11:22 +00:00
|
|
|
continue;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("nobody wants component %s\n", debugstr_w(component->Component));
|
2012-12-09 19:43:59 +00:00
|
|
|
if (component->anyAbsent && component->ComponentId)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
|
|
|
component->Action = INSTALLSTATE_ABSENT;
|
|
|
|
component->ActionRequest = INSTALLSTATE_ABSENT;
|
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (component->ActionRequest == INSTALLSTATE_DEFAULT)
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
|
|
|
TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
|
2011-03-20 08:47:41 +00:00
|
|
|
component->Action = INSTALLSTATE_LOCAL;
|
|
|
|
component->ActionRequest = INSTALLSTATE_LOCAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (component->ActionRequest == INSTALLSTATE_SOURCE &&
|
|
|
|
component->Installed == INSTALLSTATE_SOURCE &&
|
|
|
|
component->hasSourceFeature)
|
|
|
|
{
|
|
|
|
component->Action = INSTALLSTATE_UNKNOWN;
|
|
|
|
component->ActionRequest = INSTALLSTATE_UNKNOWN;
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
TRACE("component %s (installed %d request %d action %d)\n",
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
|
2012-12-09 19:43:59 +00:00
|
|
|
|
|
|
|
if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
|
|
|
|
component->num_clients++;
|
|
|
|
else if (component->Action == INSTALLSTATE_ABSENT)
|
|
|
|
component->num_clients--;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPCWSTR name;
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
|
|
|
|
name = MSI_RecordGetString( row, 1 );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
feature = msi_get_loaded_feature( package, name );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!feature)
|
|
|
|
ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LPCWSTR Condition;
|
|
|
|
Condition = MSI_RecordGetString(row,3);
|
|
|
|
|
|
|
|
if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
|
|
|
|
{
|
|
|
|
int level = MSI_RecordGetInteger(row,2);
|
2008-05-17 19:46:01 +00:00
|
|
|
TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
|
2006-02-17 00:04:10 +00:00
|
|
|
feature->Level = level;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-07-08 20:52:29 +00:00
|
|
|
static const WCHAR name[] = {'\\',0};
|
2010-10-22 16:22:21 +00:00
|
|
|
VS_FIXEDFILEINFO *ptr, *ret;
|
2006-11-28 11:21:39 +00:00
|
|
|
LPVOID version;
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
DWORD versize, handle;
|
2006-11-28 11:21:39 +00:00
|
|
|
UINT sz;
|
|
|
|
|
|
|
|
versize = GetFileVersionInfoSizeW( filename, &handle );
|
|
|
|
if (!versize)
|
|
|
|
return NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
version = msi_alloc( versize );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
if (!version)
|
|
|
|
return NULL;
|
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
GetFileVersionInfoW( filename, 0, versize, version );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-10-22 16:22:21 +00:00
|
|
|
if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz ))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
msi_free( version );
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-10-22 16:22:21 +00:00
|
|
|
ret = msi_alloc( sz );
|
|
|
|
memcpy( ret, ptr, sz );
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free( version );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
|
|
|
|
{
|
|
|
|
DWORD ms, ls;
|
|
|
|
|
|
|
|
msi_parse_version_string( version, &ms, &ls );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
if (fi->dwFileVersionMS > ms) return 1;
|
|
|
|
else if (fi->dwFileVersionMS < ms) return -1;
|
|
|
|
else if (fi->dwFileVersionLS > ls) return 1;
|
|
|
|
else if (fi->dwFileVersionLS < ls) return -1;
|
|
|
|
return 0;
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
|
|
|
|
{
|
|
|
|
DWORD ms1, ms2;
|
|
|
|
|
|
|
|
msi_parse_version_string( ver1, &ms1, NULL );
|
|
|
|
msi_parse_version_string( ver2, &ms2, NULL );
|
|
|
|
|
|
|
|
if (ms1 > ms2) return 1;
|
|
|
|
else if (ms1 < ms2) return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD msi_get_disk_file_size( LPCWSTR filename )
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
DWORD size;
|
|
|
|
|
|
|
|
file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
|
|
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
|
|
return INVALID_FILE_SIZE;
|
|
|
|
|
|
|
|
size = GetFileSize( file, NULL );
|
|
|
|
CloseHandle( file );
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
BOOL msi_file_hash_matches( MSIFILE *file )
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
MSIFILEHASHINFO hash;
|
|
|
|
|
|
|
|
hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
|
2015-07-19 23:04:25 +00:00
|
|
|
r = msi_get_filehash( file->TargetPath, &hash );
|
2010-05-29 08:55:43 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
|
|
|
|
}
|
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
static WCHAR *create_temp_dir( MSIDATABASE *db )
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
|
|
|
static UINT id;
|
2015-07-19 23:04:25 +00:00
|
|
|
WCHAR *ret;
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
if (!db->tempfolder)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2015-07-19 23:04:25 +00:00
|
|
|
WCHAR tmp[MAX_PATH];
|
2022-03-12 22:54:36 +00:00
|
|
|
UINT len = ARRAY_SIZE( tmp );
|
2015-07-19 23:04:25 +00:00
|
|
|
|
|
|
|
if (msi_get_property( db, szTempFolder, tmp, &len ) ||
|
|
|
|
GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
{
|
|
|
|
GetTempPathW( MAX_PATH, tmp );
|
|
|
|
}
|
|
|
|
if (!(db->tempfolder = strdupW( tmp ))) return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) )))
|
|
|
|
{
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (!GetTempFileNameW( db->tempfolder, szMsi, ++id, ret ))
|
|
|
|
{
|
|
|
|
msi_free( ret );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (CreateDirectoryW( ret, NULL )) break;
|
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
2015-07-19 23:04:25 +00:00
|
|
|
|
|
|
|
return ret;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
/*
|
|
|
|
* msi_build_directory_name()
|
|
|
|
*
|
|
|
|
* This function is to save messing round with directory names
|
|
|
|
* It handles adding backslashes between path segments,
|
|
|
|
* and can add \ at the end of the directory name if told to.
|
|
|
|
*
|
|
|
|
* It takes a variable number of arguments.
|
|
|
|
* It always allocates a new string for the result, so make sure
|
|
|
|
* to free the return value when finished with it.
|
|
|
|
*
|
|
|
|
* The first arg is the number of path segments that follow.
|
|
|
|
* The arguments following count are a list of path segments.
|
|
|
|
* A path segment may be NULL.
|
|
|
|
*
|
|
|
|
* Path segments will be added with a \ separating them.
|
|
|
|
* A \ will not be added after the last segment, however if the
|
|
|
|
* last segment is NULL, then the last character will be a \
|
|
|
|
*/
|
|
|
|
WCHAR *msi_build_directory_name( DWORD count, ... )
|
|
|
|
{
|
|
|
|
DWORD sz = 1, i;
|
|
|
|
WCHAR *dir;
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
va_start( va, count );
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
const WCHAR *str = va_arg( va, const WCHAR * );
|
|
|
|
if (str) sz += strlenW( str ) + 1;
|
|
|
|
}
|
|
|
|
va_end( va );
|
|
|
|
|
|
|
|
dir = msi_alloc( sz * sizeof(WCHAR) );
|
|
|
|
dir[0] = 0;
|
|
|
|
|
|
|
|
va_start( va, count );
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
const WCHAR *str = va_arg( va, const WCHAR * );
|
|
|
|
if (!str) continue;
|
|
|
|
strcatW( dir, str );
|
2012-12-09 19:43:59 +00:00
|
|
|
if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
|
|
|
va_end( va );
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
BOOL msi_is_global_assembly( MSICOMPONENT *comp )
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2015-07-19 23:04:25 +00:00
|
|
|
return comp->assembly && !comp->assembly->application;
|
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
msi_free( file->TargetPath );
|
2015-07-19 23:04:25 +00:00
|
|
|
if (msi_is_global_assembly( file->Component ))
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2015-07-19 23:04:25 +00:00
|
|
|
MSIASSEMBLY *assembly = file->Component->assembly;
|
|
|
|
|
|
|
|
if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db );
|
2012-01-21 17:19:12 +00:00
|
|
|
file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
|
|
|
|
file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
|
2015-07-19 23:04:25 +00:00
|
|
|
TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static UINT calculate_file_cost( MSIPACKAGE *package )
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
VS_FIXEDFILEINFO *file_version;
|
2011-03-20 08:47:41 +00:00
|
|
|
WCHAR *font_version;
|
2006-11-28 11:21:39 +00:00
|
|
|
MSIFILE *file;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
MSICOMPONENT *comp = file->Component;
|
2010-05-29 08:55:43 +00:00
|
|
|
DWORD file_size;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp->Enabled) continue;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
if (file->IsCompressed)
|
|
|
|
comp->ForceLocalState = TRUE;
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
set_target_path( package, file );
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if ((comp->assembly && !comp->assembly->installed) ||
|
|
|
|
GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
comp->Cost += file->FileSize;
|
|
|
|
continue;
|
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
file_size = msi_get_disk_file_size( file->TargetPath );
|
2015-07-19 23:04:25 +00:00
|
|
|
TRACE("%s (size %u)\n", debugstr_w(file->TargetPath), file_size);
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (file->Version)
|
|
|
|
{
|
|
|
|
if ((file_version = msi_get_disk_file_version( file->TargetPath )))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (msi_compare_file_versions( file_version, file->Version ) < 0)
|
|
|
|
{
|
|
|
|
comp->Cost += file->FileSize - file_size;
|
|
|
|
}
|
|
|
|
msi_free( file_version );
|
|
|
|
continue;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
else if ((font_version = msi_font_version_from_file( file->TargetPath )))
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (msi_compare_font_versions( font_version, file->Version ) < 0)
|
|
|
|
{
|
|
|
|
comp->Cost += file->FileSize - file_size;
|
|
|
|
}
|
|
|
|
msi_free( font_version );
|
|
|
|
continue;
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
if (file_size != file->FileSize)
|
2010-05-29 08:55:43 +00:00
|
|
|
{
|
|
|
|
comp->Cost += file->FileSize - file_size;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2006-11-28 11:21:39 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
WCHAR *msi_normalize_path( const WCHAR *in )
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
const WCHAR *p = in;
|
|
|
|
WCHAR *q, *ret;
|
|
|
|
int n, len = strlenW( in ) + 2;
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL;
|
|
|
|
|
|
|
|
len = 0;
|
2012-01-21 17:19:12 +00:00
|
|
|
while (1)
|
2006-11-28 11:21:39 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
/* copy until the end of the string or a space */
|
|
|
|
while (*p != ' ' && (*q = *p))
|
|
|
|
{
|
|
|
|
p++, len++;
|
|
|
|
/* reduce many backslashes to one */
|
|
|
|
if (*p != '\\' || *q != '\\')
|
|
|
|
q++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* quit at the end of the string */
|
|
|
|
if (!*p)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* count the number of spaces */
|
|
|
|
n = 0;
|
|
|
|
while (p[n] == ' ')
|
|
|
|
n++;
|
|
|
|
|
|
|
|
/* if it's leading or trailing space, skip it */
|
|
|
|
if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
|
|
|
|
p += n;
|
|
|
|
else /* copy n spaces */
|
|
|
|
while (n && (*q++ = *p++)) n--;
|
|
|
|
}
|
2012-05-14 21:41:31 +00:00
|
|
|
while (q - ret > 0 && q[-1] == ' ') q--;
|
|
|
|
if (q - ret > 0 && q[-1] != '\\')
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
q[0] = '\\';
|
|
|
|
q[1] = 0;
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
2012-05-14 21:41:31 +00:00
|
|
|
return ret;
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
static WCHAR *get_install_location( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
HKEY hkey;
|
|
|
|
WCHAR *path;
|
|
|
|
|
|
|
|
if (!package->ProductCode) return NULL;
|
2013-09-22 16:30:18 +00:00
|
|
|
if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE )) return NULL;
|
|
|
|
if ((path = msi_reg_get_val_str( hkey, szInstallLocation )) && !path[0])
|
|
|
|
{
|
|
|
|
msi_free( path );
|
|
|
|
path = NULL;
|
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
RegCloseKey( hkey );
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
|
|
|
|
{
|
|
|
|
FolderList *fl;
|
|
|
|
MSIFOLDER *folder, *parent, *child;
|
2012-05-14 21:41:31 +00:00
|
|
|
WCHAR *path, *normalized_path;
|
2012-01-21 17:19:12 +00:00
|
|
|
|
|
|
|
TRACE("resolving %s\n", debugstr_w(name));
|
|
|
|
|
|
|
|
if (!(folder = msi_get_loaded_folder( package, name ))) return;
|
|
|
|
|
|
|
|
if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
|
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
if (!(path = get_install_location( package )) &&
|
|
|
|
(!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))))
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
path = msi_dup_property( package->db, szRootDrive );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
|
|
|
|
{
|
|
|
|
if (folder->Parent && strcmpW( folder->Directory, folder->Parent ))
|
|
|
|
{
|
|
|
|
parent = msi_get_loaded_folder( package, folder->Parent );
|
|
|
|
path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
|
|
|
|
}
|
2012-05-14 21:41:31 +00:00
|
|
|
normalized_path = msi_normalize_path( path );
|
|
|
|
msi_free( path );
|
|
|
|
if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget ))
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
|
2012-05-14 21:41:31 +00:00
|
|
|
msi_free( normalized_path );
|
2012-01-21 17:19:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, folder->Directory, normalized_path, -1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_free( folder->ResolvedTarget );
|
2012-05-14 21:41:31 +00:00
|
|
|
folder->ResolvedTarget = normalized_path;
|
2012-01-21 17:19:12 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
|
|
|
|
{
|
|
|
|
child = fl->folder;
|
|
|
|
msi_resolve_target_folder( package, child->Directory, load_prop );
|
2006-11-28 11:21:39 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
|
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
static ULONGLONG get_volume_space_required( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
ULONGLONG ret = 0;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
|
|
|
if (comp->Action == INSTALLSTATE_LOCAL) ret += comp->Cost;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT ACTION_CostFinalize(MSIPACKAGE *package)
|
|
|
|
{
|
2013-09-22 16:30:18 +00:00
|
|
|
static const WCHAR query[] =
|
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','o','n','d','i','t','i','o','n','`',0};
|
|
|
|
static const WCHAR szOutOfDiskSpace[] =
|
|
|
|
{'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
|
|
|
|
static const WCHAR szPrimaryFolder[] =
|
|
|
|
{'P','R','I','M','A','R','Y','F','O','L','D','E','R',0};
|
|
|
|
static const WCHAR szPrimaryVolumePath[] =
|
|
|
|
{'P','r','i','m','a','r','y','V','o','l','u','m','e','P','a','t','h',0};
|
|
|
|
static const WCHAR szPrimaryVolumeSpaceAvailable[] =
|
|
|
|
{'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
|
|
|
|
'A','v','a','i','l','a','b','l','e',0};
|
2015-11-21 16:44:38 +00:00
|
|
|
static const WCHAR szPrimaryVolumeSpaceRequired[] =
|
|
|
|
{'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
|
|
|
|
'R','e','q','u','i','r','e','d',0};
|
|
|
|
static const WCHAR szPrimaryVolumeSpaceRemaining[] =
|
|
|
|
{'P','r','i','m','a','r','y','V','o','l','u','m','e','S','p','a','c','e',
|
|
|
|
'R','e','m','a','i','n','i','n','g',0};
|
2014-09-23 18:32:48 +00:00
|
|
|
static const WCHAR szOutOfNoRbDiskSpace[] =
|
|
|
|
{'O','u','t','O','f','N','o','R','b','D','i','s','k','S','p','a','c','e',0};
|
2012-01-21 17:19:12 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIQUERY *view;
|
2013-09-22 16:30:18 +00:00
|
|
|
WCHAR *level, *primary_key, *primary_folder;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
|
|
|
|
|
|
|
TRACE("Building directory properties\n");
|
|
|
|
msi_resolve_target_folder( package, szTargetDir, TRUE );
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
TRACE("Evaluating component conditions\n");
|
|
|
|
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
|
|
|
if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
|
|
|
|
{
|
|
|
|
TRACE("Disabling component %s\n", debugstr_w(comp->Component));
|
|
|
|
comp->Enabled = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
comp->Enabled = TRUE;
|
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
get_client_counts( package );
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2006-11-28 11:21:39 +00:00
|
|
|
/* read components states from the registry */
|
|
|
|
ACTION_GetComponentInstallStates(package);
|
2008-12-27 15:10:14 +00:00
|
|
|
ACTION_GetFeatureInstallStates(package);
|
2006-11-28 11:21:39 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
TRACE("Evaluating feature conditions\n");
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
2010-02-06 21:28:28 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
2010-02-06 21:28:28 +00:00
|
|
|
}
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
2010-02-06 21:28:28 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
TRACE("Calculating file cost\n");
|
|
|
|
calculate_file_cost( package );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szCostingComplete, szOne, -1 );
|
2006-02-17 00:04:10 +00:00
|
|
|
/* set default run level if not set */
|
2012-01-21 17:19:12 +00:00
|
|
|
level = msi_dup_property( package->db, szInstallLevel );
|
2013-09-22 16:30:18 +00:00
|
|
|
if (!level) msi_set_property( package->db, szInstallLevel, szOne, -1 );
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(level);
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if ((rc = MSI_SetFeatureStates( package ))) return rc;
|
|
|
|
|
2013-09-22 16:30:18 +00:00
|
|
|
if ((primary_key = msi_dup_property( package->db, szPrimaryFolder )))
|
|
|
|
{
|
|
|
|
if ((primary_folder = msi_dup_property( package->db, primary_key )))
|
|
|
|
{
|
|
|
|
if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') ||
|
|
|
|
(primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':')
|
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
static const WCHAR fmtW[] = {'%','l','u',0};
|
2013-09-22 16:30:18 +00:00
|
|
|
ULARGE_INTEGER free;
|
2015-11-21 16:44:38 +00:00
|
|
|
ULONGLONG required;
|
|
|
|
WCHAR buf[21];
|
2013-09-22 16:30:18 +00:00
|
|
|
|
|
|
|
primary_folder[2] = 0;
|
|
|
|
if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL ))
|
|
|
|
{
|
|
|
|
sprintfW( buf, fmtW, free.QuadPart / 512 );
|
|
|
|
msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 );
|
|
|
|
}
|
2015-11-21 16:44:38 +00:00
|
|
|
required = get_volume_space_required( package );
|
|
|
|
sprintfW( buf, fmtW, required / 512 );
|
|
|
|
msi_set_property( package->db, szPrimaryVolumeSpaceRequired, buf, -1 );
|
|
|
|
|
|
|
|
sprintfW( buf, fmtW, (free.QuadPart - required) / 512 );
|
|
|
|
msi_set_property( package->db, szPrimaryVolumeSpaceRemaining, buf, -1 );
|
2013-09-22 16:30:18 +00:00
|
|
|
msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 );
|
|
|
|
}
|
|
|
|
msi_free( primary_folder );
|
|
|
|
}
|
|
|
|
msi_free( primary_key );
|
|
|
|
}
|
|
|
|
|
2008-05-17 19:46:01 +00:00
|
|
|
/* FIXME: check volume disk space */
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szOutOfDiskSpace, szZero, -1 );
|
2014-09-23 18:32:48 +00:00
|
|
|
msi_set_property( package->db, szOutOfNoRbDiskSpace, szZero, -1 );
|
2008-05-17 19:46:01 +00:00
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
BYTE *data;
|
2008-02-10 13:16:32 +00:00
|
|
|
|
2012-08-13 16:17:18 +00:00
|
|
|
if (!value)
|
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
*size = sizeof(WCHAR);
|
2012-08-13 16:17:18 +00:00
|
|
|
*type = REG_SZ;
|
2012-12-09 19:43:59 +00:00
|
|
|
if ((data = msi_alloc( *size ))) *(WCHAR *)data = 0;
|
2012-08-13 16:17:18 +00:00
|
|
|
return data;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
if (value[0]=='#' && value[1]!='#' && value[1]!='%')
|
|
|
|
{
|
|
|
|
if (value[1]=='x')
|
|
|
|
{
|
|
|
|
LPWSTR ptr;
|
|
|
|
CHAR byte[5];
|
|
|
|
LPWSTR deformated = NULL;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
deformat_string(package, &value[2], &deformated);
|
|
|
|
|
|
|
|
/* binary value type */
|
|
|
|
ptr = deformated;
|
|
|
|
*type = REG_BINARY;
|
|
|
|
if (strlenW(ptr)%2)
|
|
|
|
*size = (strlenW(ptr)/2)+1;
|
|
|
|
else
|
|
|
|
*size = strlenW(ptr)/2;
|
|
|
|
|
|
|
|
data = msi_alloc(*size);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
byte[0] = '0';
|
|
|
|
byte[1] = 'x';
|
|
|
|
byte[4] = 0;
|
2006-02-17 00:04:10 +00:00
|
|
|
count = 0;
|
|
|
|
/* if uneven pad with a zero in front */
|
|
|
|
if (strlenW(ptr)%2)
|
|
|
|
{
|
|
|
|
byte[2]= '0';
|
|
|
|
byte[3]= *ptr;
|
|
|
|
ptr++;
|
|
|
|
data[count] = (BYTE)strtol(byte,NULL,0);
|
|
|
|
count ++;
|
|
|
|
TRACE("Uneven byte count\n");
|
|
|
|
}
|
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
byte[2]= *ptr;
|
|
|
|
ptr++;
|
|
|
|
byte[3]= *ptr;
|
|
|
|
ptr++;
|
|
|
|
data[count] = (BYTE)strtol(byte,NULL,0);
|
|
|
|
count ++;
|
|
|
|
}
|
|
|
|
msi_free(deformated);
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("Data %i bytes(%i)\n",*size,count);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LPWSTR deformated;
|
|
|
|
LPWSTR p;
|
|
|
|
DWORD d = 0;
|
|
|
|
deformat_string(package, &value[1], &deformated);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
*type=REG_DWORD;
|
2006-02-17 00:04:10 +00:00
|
|
|
*size = sizeof(DWORD);
|
|
|
|
data = msi_alloc(*size);
|
|
|
|
p = deformated;
|
|
|
|
if (*p == '-')
|
|
|
|
p++;
|
|
|
|
while (*p)
|
|
|
|
{
|
|
|
|
if ( (*p < '0') || (*p > '9') )
|
|
|
|
break;
|
|
|
|
d *= 10;
|
|
|
|
d += (*p - '0');
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (deformated[0] == '-')
|
|
|
|
d = -d;
|
|
|
|
*(LPDWORD)data = d;
|
2006-10-22 20:23:59 +00:00
|
|
|
TRACE("DWORD %i\n",*(LPDWORD)data);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
msi_free(deformated);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
const WCHAR *ptr = value;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
*type = REG_SZ;
|
|
|
|
if (value[0] == '#')
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
ptr++; len--;
|
2012-12-09 19:43:59 +00:00
|
|
|
if (value[1] == '%')
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
ptr++; len--;
|
2012-12-09 19:43:59 +00:00
|
|
|
*type = REG_EXPAND_SZ;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-02-10 13:16:32 +00:00
|
|
|
}
|
2015-03-09 20:28:19 +00:00
|
|
|
data = (BYTE *)msi_strdupW( ptr, len );
|
2012-12-09 19:43:59 +00:00
|
|
|
if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
|
|
|
|
*size = (len + 1) * sizeof(WCHAR);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
|
|
|
|
{
|
|
|
|
const WCHAR *ret;
|
|
|
|
|
|
|
|
switch (root)
|
|
|
|
{
|
|
|
|
case -1:
|
2010-05-29 08:55:43 +00:00
|
|
|
if (msi_get_property_int( package->db, szAllUsers, 0 ))
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
|
|
|
*root_key = HKEY_LOCAL_MACHINE;
|
|
|
|
ret = szHLM;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*root_key = HKEY_CURRENT_USER;
|
|
|
|
ret = szHCU;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
*root_key = HKEY_CLASSES_ROOT;
|
|
|
|
ret = szHCR;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*root_key = HKEY_CURRENT_USER;
|
|
|
|
ret = szHCU;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
*root_key = HKEY_LOCAL_MACHINE;
|
|
|
|
ret = szHLM;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
*root_key = HKEY_USERS;
|
|
|
|
ret = szHU;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ERR("Unknown root %i\n", root);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
static inline REGSAM get_registry_view( const MSICOMPONENT *comp )
|
2010-10-22 13:18:11 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
REGSAM view = 0;
|
|
|
|
if (is_wow64 || is_64bit)
|
|
|
|
view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
|
|
|
|
return view;
|
2010-10-22 13:18:11 +00:00
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create, REGSAM access )
|
2012-08-13 16:17:18 +00:00
|
|
|
{
|
|
|
|
WCHAR *subkey, *p, *q;
|
|
|
|
HKEY hkey, ret = NULL;
|
|
|
|
LONG res;
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
access |= get_registry_view( comp );
|
2012-08-13 16:17:18 +00:00
|
|
|
|
|
|
|
if (!(subkey = strdupW( path ))) return NULL;
|
|
|
|
p = subkey;
|
|
|
|
if ((q = strchrW( p, '\\' ))) *q = 0;
|
|
|
|
if (create)
|
|
|
|
res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
|
|
|
|
else
|
|
|
|
res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
|
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res);
|
|
|
|
msi_free( subkey );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (q && q[1])
|
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
ret = open_key( comp, hkey, q + 1, create, access );
|
2012-08-13 16:17:18 +00:00
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
|
|
|
else ret = hkey;
|
|
|
|
msi_free( subkey );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL is_special_entry( const WCHAR *name )
|
|
|
|
{
|
|
|
|
return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
|
|
|
|
}
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
|
|
|
|
{
|
|
|
|
const WCHAR *p = str;
|
|
|
|
WCHAR **ret;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
*count = 0;
|
|
|
|
if (!str) return NULL;
|
|
|
|
while ((p - str) < len)
|
|
|
|
{
|
|
|
|
p += strlenW( p ) + 1;
|
|
|
|
(*count)++;
|
|
|
|
}
|
|
|
|
if (!(ret = msi_alloc( *count * sizeof(WCHAR *) ))) return NULL;
|
|
|
|
p = str;
|
|
|
|
while ((p - str) < len)
|
|
|
|
{
|
|
|
|
if (!(ret[i] = strdupW( p )))
|
|
|
|
{
|
|
|
|
for (; i >= 0; i--) msi_free( ret[i] );
|
|
|
|
msi_free( ret );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
p += strlenW( p ) + 1;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
|
|
|
|
WCHAR **right, DWORD right_count, DWORD *size )
|
|
|
|
{
|
|
|
|
WCHAR *ret, *p;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
*size = sizeof(WCHAR);
|
|
|
|
for (i = 0; i < left_count; i++) *size += (strlenW( left[i] ) + 1) * sizeof(WCHAR);
|
|
|
|
for (i = 0; i < right_count; i++) *size += (strlenW( right[i] ) + 1) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
if (!(ret = p = msi_alloc( *size ))) return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < left_count; i++)
|
|
|
|
{
|
|
|
|
strcpyW( p, left[i] );
|
|
|
|
p += strlenW( p ) + 1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < right_count; i++)
|
|
|
|
{
|
|
|
|
strcpyW( p, right[i] );
|
|
|
|
p += strlenW( p ) + 1;
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
|
|
|
|
WCHAR **new, DWORD new_count )
|
|
|
|
{
|
|
|
|
DWORD ret = old_count;
|
|
|
|
unsigned int i, j, k;
|
|
|
|
|
|
|
|
for (i = 0; i < new_count; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < old_count; j++)
|
|
|
|
{
|
|
|
|
if (old[j] && !strcmpW( new[i], old[j] ))
|
|
|
|
{
|
|
|
|
msi_free( old[j] );
|
|
|
|
for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
|
|
|
|
old[k] = NULL;
|
|
|
|
ret--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum join_op
|
|
|
|
{
|
|
|
|
JOIN_OP_APPEND,
|
|
|
|
JOIN_OP_PREPEND,
|
|
|
|
JOIN_OP_REPLACE
|
|
|
|
};
|
|
|
|
|
|
|
|
static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
|
|
|
|
WCHAR **new, DWORD new_count, DWORD *size )
|
|
|
|
{
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case JOIN_OP_APPEND:
|
|
|
|
old_count = remove_duplicate_values( old, old_count, new, new_count );
|
|
|
|
return flatten_multi_string_values( old, old_count, new, new_count, size );
|
|
|
|
|
|
|
|
case JOIN_OP_PREPEND:
|
|
|
|
old_count = remove_duplicate_values( old, old_count, new, new_count );
|
|
|
|
return flatten_multi_string_values( new, new_count, old, old_count, size );
|
|
|
|
|
|
|
|
case JOIN_OP_REPLACE:
|
|
|
|
return flatten_multi_string_values( new, new_count, NULL, 0, size );
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERR("unhandled join op %u\n", op);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
|
|
|
|
BYTE *new_value, DWORD new_size, DWORD *size )
|
|
|
|
{
|
|
|
|
DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
|
|
|
|
const WCHAR *new_ptr = NULL, *old_ptr = NULL;
|
|
|
|
enum join_op op = JOIN_OP_REPLACE;
|
|
|
|
WCHAR **old = NULL, **new = NULL;
|
|
|
|
BYTE *ret;
|
|
|
|
|
|
|
|
if (new_size / sizeof(WCHAR) - 1 > 1)
|
|
|
|
{
|
|
|
|
new_ptr = (const WCHAR *)new_value;
|
|
|
|
new_len = new_size / sizeof(WCHAR) - 1;
|
|
|
|
|
|
|
|
if (!new_ptr[0] && new_ptr[new_len - 1])
|
|
|
|
{
|
|
|
|
op = JOIN_OP_APPEND;
|
|
|
|
new_len--;
|
|
|
|
new_ptr++;
|
|
|
|
}
|
|
|
|
else if (new_ptr[0] && !new_ptr[new_len - 1])
|
|
|
|
{
|
|
|
|
op = JOIN_OP_PREPEND;
|
|
|
|
new_len--;
|
|
|
|
}
|
|
|
|
else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
|
|
|
|
{
|
|
|
|
op = JOIN_OP_REPLACE;
|
|
|
|
new_len -= 2;
|
|
|
|
new_ptr++;
|
|
|
|
}
|
|
|
|
new = split_multi_string_values( new_ptr, new_len, &new_count );
|
|
|
|
}
|
|
|
|
if (old_size / sizeof(WCHAR) - 1 > 1)
|
|
|
|
{
|
|
|
|
old_ptr = (const WCHAR *)old_value;
|
|
|
|
old_len = old_size / sizeof(WCHAR) - 1;
|
|
|
|
old = split_multi_string_values( old_ptr, old_len, &old_count );
|
|
|
|
}
|
|
|
|
ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
|
|
|
|
for (i = 0; i < old_count; i++) msi_free( old[i] );
|
|
|
|
for (i = 0; i < new_count; i++) msi_free( new[i] );
|
|
|
|
msi_free( old );
|
|
|
|
msi_free( new );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
|
|
|
|
{
|
|
|
|
BYTE *ret;
|
|
|
|
if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
|
|
|
|
if (!(ret = msi_alloc( *size ))) return NULL;
|
|
|
|
RegQueryValueExW( hkey, name, NULL, type, ret, size );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2012-12-09 19:43:59 +00:00
|
|
|
BYTE *new_value, *old_value = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
HKEY root_key, hkey;
|
2012-12-09 19:43:59 +00:00
|
|
|
DWORD type, old_type, new_size, old_size = 0;
|
2015-03-09 20:28:19 +00:00
|
|
|
LPWSTR deformated, uikey;
|
2012-12-09 19:43:59 +00:00
|
|
|
const WCHAR *szRoot, *component, *name, *key, *str;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD * uirow;
|
|
|
|
INT root;
|
|
|
|
BOOL check_first = FALSE;
|
2012-12-09 19:43:59 +00:00
|
|
|
int len;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
component = MSI_RecordGetString(row, 6);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package,component);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
2018-03-04 23:30:58 +00:00
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL && comp->Action != INSTALLSTATE_SOURCE)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = MSI_RecordGetString(row, 4);
|
|
|
|
if( MSI_RecordIsNull(row,5) && name )
|
|
|
|
{
|
|
|
|
/* null values can have special meanings */
|
|
|
|
if (name[0]=='-' && name[1] == 0)
|
|
|
|
return ERROR_SUCCESS;
|
2012-08-13 16:17:18 +00:00
|
|
|
if ((name[0] == '+' || name[0] == '*') && !name[1])
|
|
|
|
check_first = TRUE;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
root = MSI_RecordGetInteger(row,2);
|
|
|
|
key = MSI_RecordGetString(row, 3);
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
szRoot = get_root_key( package, root, &root_key );
|
|
|
|
if (!szRoot)
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
deformat_string(package, key , &deformated);
|
2012-12-09 19:43:59 +00:00
|
|
|
uikey = msi_alloc( (strlenW(deformated) + strlenW(szRoot) + 1) * sizeof(WCHAR) );
|
2006-02-17 00:04:10 +00:00
|
|
|
strcpyW(uikey,szRoot);
|
|
|
|
strcatW(uikey,deformated);
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (!(hkey = open_key( comp, root_key, deformated, TRUE, KEY_QUERY_VALUE | KEY_SET_VALUE )))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
ERR("Could not create key %s\n", debugstr_w(deformated));
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(uikey);
|
2015-03-09 20:28:19 +00:00
|
|
|
msi_free(deformated);
|
2012-08-13 16:17:18 +00:00
|
|
|
return ERROR_FUNCTION_FAILED;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2015-03-09 20:28:19 +00:00
|
|
|
msi_free( deformated );
|
|
|
|
str = msi_record_get_string( row, 5, NULL );
|
|
|
|
len = deformat_string( package, str, &deformated );
|
|
|
|
new_value = parse_value( package, deformated, len, &type, &new_size );
|
|
|
|
|
|
|
|
msi_free( deformated );
|
2006-02-17 00:04:10 +00:00
|
|
|
deformat_string(package, name, &deformated);
|
|
|
|
|
2012-08-13 16:17:18 +00:00
|
|
|
if (!is_special_entry( name ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
|
|
|
|
if (type == REG_MULTI_SZ)
|
|
|
|
{
|
|
|
|
BYTE *new;
|
|
|
|
if (old_value && old_type != REG_MULTI_SZ)
|
|
|
|
{
|
|
|
|
msi_free( old_value );
|
|
|
|
old_value = NULL;
|
|
|
|
old_size = 0;
|
|
|
|
}
|
|
|
|
new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
|
|
|
|
msi_free( new_value );
|
|
|
|
new_value = new;
|
|
|
|
}
|
2012-08-13 16:17:18 +00:00
|
|
|
if (!check_first)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
|
|
|
|
RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
else if (!old_value)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
if (deformated || new_size)
|
2012-08-13 16:17:18 +00:00
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
TRACE("setting value %s of %s type %u\n", debugstr_w(deformated), debugstr_w(uikey), type);
|
|
|
|
RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
|
2012-08-13 16:17:18 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord(3);
|
|
|
|
MSI_RecordSetStringW(uirow,2,deformated);
|
|
|
|
MSI_RecordSetStringW(uirow,1,uikey);
|
2010-05-29 08:55:43 +00:00
|
|
|
if (type == REG_SZ || type == REG_EXPAND_SZ)
|
2012-12-09 19:43:59 +00:00
|
|
|
MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_free(new_value);
|
|
|
|
msi_free(old_value);
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(deformated);
|
|
|
|
msi_free(uikey);
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','R','e','g','i','s','t','r','y','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szWriteRegistryValues);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-03-12 15:34:04 +00:00
|
|
|
static int is_key_empty(const MSICOMPONENT *comp, HKEY root, const WCHAR *path)
|
|
|
|
{
|
|
|
|
DWORD subkeys, values;
|
|
|
|
HKEY key;
|
|
|
|
LONG res;
|
|
|
|
|
|
|
|
key = open_key(comp, root, path, FALSE, get_registry_view(comp) | KEY_READ);
|
|
|
|
if (!key) return 0;
|
|
|
|
|
|
|
|
res = RegQueryInfoKeyW(key, 0, 0, 0, &subkeys, 0, 0, &values, 0, 0, 0, 0);
|
|
|
|
RegCloseKey(key);
|
|
|
|
|
|
|
|
return !res && !subkeys && !values;
|
|
|
|
}
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
|
2012-08-13 16:17:18 +00:00
|
|
|
{
|
2022-03-12 15:34:04 +00:00
|
|
|
LONG res = ERROR_SUCCESS;
|
2012-08-13 16:17:18 +00:00
|
|
|
REGSAM access = 0;
|
|
|
|
WCHAR *subkey, *p;
|
|
|
|
HKEY hkey;
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
access |= get_registry_view( comp );
|
2012-08-13 16:17:18 +00:00
|
|
|
|
|
|
|
if (!(subkey = strdupW( path ))) return;
|
2015-11-21 16:44:38 +00:00
|
|
|
do
|
2012-08-13 16:17:18 +00:00
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
if ((p = strrchrW( subkey, '\\' )))
|
|
|
|
{
|
|
|
|
*p = 0;
|
|
|
|
if (!p[1]) continue; /* trailing backslash */
|
2015-11-27 11:34:12 +00:00
|
|
|
hkey = open_key( comp, root, subkey, FALSE, access | READ_CONTROL );
|
2015-11-21 16:44:38 +00:00
|
|
|
if (!hkey) break;
|
2022-03-12 15:34:04 +00:00
|
|
|
if (!is_key_empty(comp, hkey, p + 1))
|
|
|
|
{
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
break;
|
|
|
|
}
|
2012-08-13 16:17:18 +00:00
|
|
|
res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
|
2015-11-21 16:44:38 +00:00
|
|
|
RegCloseKey( hkey );
|
|
|
|
}
|
2022-03-12 15:34:04 +00:00
|
|
|
else if (is_key_empty(comp, root, subkey))
|
2012-08-13 16:17:18 +00:00
|
|
|
res = RegDeleteKeyExW( root, subkey, access, 0 );
|
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res);
|
|
|
|
break;
|
|
|
|
}
|
2015-11-21 16:44:38 +00:00
|
|
|
} while (p);
|
2012-08-13 16:17:18 +00:00
|
|
|
msi_free( subkey );
|
|
|
|
}
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value )
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
|
|
|
LONG res;
|
|
|
|
HKEY hkey;
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if ((hkey = open_key( comp, root, path, FALSE, KEY_SET_VALUE | KEY_QUERY_VALUE )))
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
|
|
|
if ((res = RegDeleteValueW( hkey, value )))
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res);
|
2012-08-13 16:17:18 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
RegCloseKey( hkey );
|
2022-03-12 15:34:04 +00:00
|
|
|
if (is_key_empty(comp, root, path))
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2012-08-13 16:17:18 +00:00
|
|
|
TRACE("removing empty key %s\n", debugstr_w(path));
|
2015-03-09 20:28:19 +00:00
|
|
|
delete_key( comp, root, path );
|
2010-03-06 09:05:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
2012-08-13 16:17:18 +00:00
|
|
|
LONG res;
|
|
|
|
HKEY hkey;
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (!(hkey = open_key( comp, root, path, FALSE, KEY_ALL_ACCESS ))) return;
|
|
|
|
res = RegDeleteTreeW( hkey, NULL );
|
2012-08-13 16:17:18 +00:00
|
|
|
if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res);
|
2015-03-09 20:28:19 +00:00
|
|
|
delete_key( comp, root, path );
|
2012-08-13 16:17:18 +00:00
|
|
|
RegCloseKey( hkey );
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR component, name, key_str, root_key_str;
|
2015-03-09 20:28:19 +00:00
|
|
|
LPWSTR deformated_key, deformated_name, ui_key_str;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
BOOL delete_key = FALSE;
|
|
|
|
HKEY hkey_root;
|
|
|
|
UINT size;
|
|
|
|
INT root;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 6 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2010-03-06 09:05:09 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = MSI_RecordGetString( row, 4 );
|
|
|
|
if (MSI_RecordIsNull( row, 5 ) && name )
|
|
|
|
{
|
|
|
|
if (name[0] == '+' && !name[1])
|
|
|
|
return ERROR_SUCCESS;
|
2012-08-13 16:17:18 +00:00
|
|
|
if ((name[0] == '-' || name[0] == '*') && !name[1])
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
|
|
|
delete_key = TRUE;
|
|
|
|
name = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
root = MSI_RecordGetInteger( row, 2 );
|
|
|
|
key_str = MSI_RecordGetString( row, 3 );
|
|
|
|
|
|
|
|
root_key_str = get_root_key( package, root, &hkey_root );
|
|
|
|
if (!root_key_str)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
deformat_string( package, key_str, &deformated_key );
|
|
|
|
size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
|
|
|
|
ui_key_str = msi_alloc( size * sizeof(WCHAR) );
|
|
|
|
strcpyW( ui_key_str, root_key_str );
|
|
|
|
strcatW( ui_key_str, deformated_key );
|
|
|
|
|
|
|
|
deformat_string( package, name, &deformated_name );
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
if (delete_key) delete_tree( comp, hkey_root, deformated_key );
|
|
|
|
else delete_value( comp, hkey_root, deformated_key, deformated_name );
|
2010-03-06 09:05:09 +00:00
|
|
|
msi_free( deformated_key );
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, deformated_name );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free( ui_key_str );
|
|
|
|
msi_free( deformated_name );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR component, name, key_str, root_key_str;
|
2015-03-09 20:28:19 +00:00
|
|
|
LPWSTR deformated_key, deformated_name, ui_key_str;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
BOOL delete_key = FALSE;
|
|
|
|
HKEY hkey_root;
|
|
|
|
UINT size;
|
|
|
|
INT root;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 5 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2010-03-06 09:05:09 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((name = MSI_RecordGetString( row, 4 )))
|
|
|
|
{
|
|
|
|
if (name[0] == '-' && !name[1])
|
|
|
|
{
|
|
|
|
delete_key = TRUE;
|
|
|
|
name = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
root = MSI_RecordGetInteger( row, 2 );
|
|
|
|
key_str = MSI_RecordGetString( row, 3 );
|
|
|
|
|
|
|
|
root_key_str = get_root_key( package, root, &hkey_root );
|
|
|
|
if (!root_key_str)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
deformat_string( package, key_str, &deformated_key );
|
|
|
|
size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1;
|
|
|
|
ui_key_str = msi_alloc( size * sizeof(WCHAR) );
|
|
|
|
strcpyW( ui_key_str, root_key_str );
|
|
|
|
strcatW( ui_key_str, deformated_key );
|
|
|
|
|
|
|
|
deformat_string( package, name, &deformated_name );
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
if (delete_key) delete_tree( comp, hkey_root, deformated_key );
|
|
|
|
else delete_value( comp, hkey_root, deformated_key, deformated_name );
|
2010-03-06 09:05:09 +00:00
|
|
|
msi_free( deformated_key );
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, ui_key_str );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, deformated_name );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free( ui_key_str );
|
|
|
|
msi_free( deformated_name );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR registry_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','R','e','g','i','s','t','r','y','`',0};
|
|
|
|
static const WCHAR remove_registry_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0};
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2010-03-06 09:05:09 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveRegistryValues);
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view );
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static UINT ACTION_InstallValidate(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[]= {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
|
|
|
'`','R','e','g','i','s','t','r','y','`',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
MSICOMPONENT *comp;
|
2012-01-21 17:19:12 +00:00
|
|
|
DWORD total = 0, count = 0;
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSIFEATURE *feature;
|
|
|
|
MSIFILE *file;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
TRACE("InstallValidate\n");
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_IterateRecords( view, &count, NULL, package );
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
total += count * REG_PROGRESS_VALUE;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
|
|
|
|
total += COMPONENT_PROGRESS_VALUE;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
|
|
|
total += file->FileSize;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_ui_progress( package, 0, total, 0, 0 );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
TRACE("Feature: %s Installed %d Request %d Action %d\n",
|
|
|
|
debugstr_w(feature->Feature), feature->Installed,
|
|
|
|
feature->ActionRequest, feature->Action);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE* package = param;
|
2008-01-16 10:11:22 +00:00
|
|
|
LPCWSTR cond = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPCWSTR message = NULL;
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT r;
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static const WCHAR title[]=
|
|
|
|
{'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
|
|
|
|
|
|
|
|
cond = MSI_RecordGetString(row,1);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
r = MSI_EvaluateConditionW(package,cond);
|
|
|
|
if (r == MSICONDITION_FALSE)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
LPWSTR deformated;
|
|
|
|
message = MSI_RecordGetString(row,2);
|
|
|
|
deformat_string(package,message,&deformated);
|
|
|
|
MessageBoxW(NULL,deformated,title,MB_OK);
|
|
|
|
msi_free(deformated);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
|
|
|
TRACE("Checking launch conditions\n");
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!cmp->KeyPath)
|
2012-01-21 17:19:12 +00:00
|
|
|
return strdupW( msi_get_target_folder( package, cmp->Directory ) );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0};
|
|
|
|
static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0};
|
|
|
|
static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0};
|
|
|
|
MSIRECORD *row;
|
|
|
|
UINT root, len;
|
|
|
|
LPWSTR deformated, buffer, deformated_name;
|
|
|
|
LPCWSTR key, name;
|
|
|
|
|
|
|
|
row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!row)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
root = MSI_RecordGetInteger(row,2);
|
|
|
|
key = MSI_RecordGetString(row, 3);
|
|
|
|
name = MSI_RecordGetString(row, 4);
|
|
|
|
deformat_string(package, key , &deformated);
|
|
|
|
deformat_string(package, name, &deformated_name);
|
|
|
|
|
|
|
|
len = strlenW(deformated) + 6;
|
|
|
|
if (deformated_name)
|
|
|
|
len+=strlenW(deformated_name);
|
|
|
|
|
|
|
|
buffer = msi_alloc( len *sizeof(WCHAR));
|
|
|
|
|
|
|
|
if (deformated_name)
|
|
|
|
sprintfW(buffer,fmt2,root,deformated,deformated_name);
|
|
|
|
else
|
|
|
|
sprintfW(buffer,fmt,root,deformated);
|
|
|
|
|
|
|
|
msi_free(deformated);
|
|
|
|
msi_free(deformated_name);
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
|
|
|
|
{
|
|
|
|
FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (file)
|
|
|
|
return strdupW( file->TargetPath );
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HKEY openSharedDLLsKey(void)
|
|
|
|
{
|
|
|
|
HKEY hkey=0;
|
|
|
|
static const WCHAR path[] =
|
|
|
|
{'S','o','f','t','w','a','r','e','\\',
|
|
|
|
'M','i','c','r','o','s','o','f','t','\\',
|
|
|
|
'W','i','n','d','o','w','s','\\',
|
|
|
|
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
|
|
|
'S','h','a','r','e','d','D','L','L','s',0};
|
|
|
|
|
|
|
|
RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
|
|
|
|
return hkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
|
|
|
|
{
|
|
|
|
HKEY hkey;
|
|
|
|
DWORD count=0;
|
|
|
|
DWORD type;
|
|
|
|
DWORD sz = sizeof(count);
|
|
|
|
DWORD rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
hkey = openSharedDLLsKey();
|
|
|
|
rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
count = 0;
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
|
|
|
|
{
|
|
|
|
HKEY hkey;
|
|
|
|
|
|
|
|
hkey = openSharedDLLsKey();
|
|
|
|
if (count > 0)
|
|
|
|
msi_reg_set_val_dword( hkey, path, count );
|
|
|
|
else
|
|
|
|
RegDeleteValueW(hkey,path);
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
INT count = 0;
|
|
|
|
BOOL write = FALSE;
|
|
|
|
|
|
|
|
/* only refcount DLLs */
|
2008-01-16 10:11:22 +00:00
|
|
|
if (comp->KeyPath == NULL ||
|
2011-03-20 08:47:41 +00:00
|
|
|
comp->assembly ||
|
2008-01-16 10:11:22 +00:00
|
|
|
comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
|
2006-02-17 00:04:10 +00:00
|
|
|
comp->Attributes & msidbComponentAttributesODBCDataSource)
|
|
|
|
write = FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
|
|
|
|
write = (count > 0);
|
|
|
|
|
|
|
|
if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
|
|
|
|
write = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* increment counts */
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
|
|
|
ComponentList *cl;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
|
2006-02-17 00:04:10 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
|
|
|
|
{
|
|
|
|
if ( cl->component == comp )
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* decrement counts */
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
|
|
|
ComponentList *cl;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
|
2006-02-17 00:04:10 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
|
|
|
|
{
|
|
|
|
if ( cl->component == comp )
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ref count all the files in the component */
|
|
|
|
if (write)
|
|
|
|
{
|
|
|
|
MSIFILE *file;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
|
|
|
{
|
|
|
|
if (file->Component == comp)
|
|
|
|
ACTION_WriteSharedDLLsCount( file->TargetPath, count );
|
|
|
|
}
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2008-05-17 19:46:01 +00:00
|
|
|
/* add a count for permanent */
|
2006-02-17 00:04:10 +00:00
|
|
|
if (comp->Attributes & msidbComponentAttributesPermanent)
|
|
|
|
count ++;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
comp->RefCount = count;
|
|
|
|
|
|
|
|
if (write)
|
|
|
|
ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
|
|
|
|
{
|
|
|
|
if (comp->assembly)
|
|
|
|
{
|
|
|
|
const WCHAR prefixW[] = {'<','\\',0};
|
|
|
|
DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name );
|
|
|
|
WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) );
|
|
|
|
|
|
|
|
if (keypath)
|
|
|
|
{
|
|
|
|
strcpyW( keypath, prefixW );
|
|
|
|
strcatW( keypath, comp->assembly->display_name );
|
|
|
|
}
|
|
|
|
return keypath;
|
|
|
|
}
|
|
|
|
return resolve_keypath( package, comp );
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR squashed_pc[SQUASHED_GUID_SIZE], squashed_cc[SQUASHED_GUID_SIZE];
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
MSICOMPONENT *comp;
|
2008-07-08 20:52:29 +00:00
|
|
|
HKEY hkey;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
TRACE("\n");
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
msi_set_sourcedir_props(package, FALSE);
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szProcessComponents);
|
|
|
|
|
|
|
|
squash_guid( package->ProductCode, squashed_pc );
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIRECORD *uirow;
|
|
|
|
INSTALLSTATE action;
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (!comp->ComponentId)
|
|
|
|
continue;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
squash_guid( comp->ComponentId, squashed_cc );
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_free( comp->FullKeypath );
|
|
|
|
comp->FullKeypath = build_full_keypath( package, comp );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
ACTION_RefCountComponent( package, comp );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (package->need_rollback) action = comp->Installed;
|
|
|
|
else action = comp->ActionRequest;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
|
2016-11-22 12:25:27 +00:00
|
|
|
debugstr_w(comp->Component), debugstr_w(squashed_cc),
|
2012-12-09 19:43:59 +00:00
|
|
|
debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
|
2012-01-21 17:19:12 +00:00
|
|
|
|
|
|
|
if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2008-07-08 20:52:29 +00:00
|
|
|
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
|
2011-03-20 08:47:41 +00:00
|
|
|
rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE);
|
2008-07-08 20:52:29 +00:00
|
|
|
else
|
2011-03-20 08:47:41 +00:00
|
|
|
rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
|
2008-07-08 20:52:29 +00:00
|
|
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
continue;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
if (comp->Attributes & msidbComponentAttributesPermanent)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
static const WCHAR szPermKey[] =
|
|
|
|
{ '0','0','0','0','0','0','0','0','0','0','0','0',
|
|
|
|
'0','0','0','0','0','0','0','0','0','0','0','0',
|
|
|
|
'0','0','0','0','0','0','0','0',0 };
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
if (action == INSTALLSTATE_LOCAL)
|
2016-11-22 12:25:27 +00:00
|
|
|
msi_reg_set_val_str( hkey, squashed_pc, comp->FullKeypath );
|
2008-12-27 15:10:14 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
MSIFILE *file;
|
|
|
|
MSIRECORD *row;
|
|
|
|
LPWSTR ptr, ptr2;
|
|
|
|
WCHAR source[MAX_PATH];
|
|
|
|
WCHAR base[MAX_PATH];
|
|
|
|
LPWSTR sourcepath;
|
|
|
|
|
|
|
|
static const WCHAR fmt[] = {'%','0','2','d','\\',0};
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
|
|
|
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
|
|
|
|
'>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
|
|
|
|
'`','D','i','s','k','I','d','`',0};
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
|
2008-12-27 15:10:14 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (!(row = MSI_QueryGetRecord(package->db, query, file->Sequence)))
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
|
|
|
|
ptr2 = strrchrW(source, '\\') + 1;
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
|
|
|
|
lstrcpyW(base, package->PackagePath);
|
|
|
|
ptr = strrchrW(base, '\\');
|
|
|
|
*(ptr + 1) = '\0';
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
sourcepath = msi_resolve_file_source(package, file);
|
2008-12-27 15:10:14 +00:00
|
|
|
ptr = sourcepath + lstrlenW(base);
|
|
|
|
lstrcpyW(ptr2, ptr);
|
|
|
|
msi_free(sourcepath);
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
msi_reg_set_val_str( hkey, squashed_pc, source );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2008-07-08 20:52:29 +00:00
|
|
|
RegCloseKey(hkey);
|
2006-08-01 23:12:11 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
else if (action == INSTALLSTATE_ABSENT)
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2012-12-09 19:43:59 +00:00
|
|
|
if (comp->num_clients <= 0)
|
|
|
|
{
|
|
|
|
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
|
2014-04-23 14:48:52 +00:00
|
|
|
rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid );
|
2012-12-09 19:43:59 +00:00
|
|
|
else
|
2014-04-23 14:48:52 +00:00
|
|
|
rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
|
|
|
|
|
|
|
|
if (rc != ERROR_SUCCESS) WARN( "failed to delete component key %u\n", rc );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LONG res;
|
|
|
|
|
|
|
|
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE );
|
|
|
|
else
|
|
|
|
rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE );
|
|
|
|
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WARN( "failed to open component key %u\n", rc );
|
|
|
|
continue;
|
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
res = RegDeleteValueW( hkey, squashed_pc );
|
2014-04-23 14:48:52 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
if (res) WARN( "failed to delete component value %d\n", res );
|
2012-12-09 19:43:59 +00:00
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
/* UI stuff */
|
|
|
|
uirow = MSI_CreateRecord(3);
|
|
|
|
MSI_RecordSetStringW(uirow,1,package->ProductCode);
|
|
|
|
MSI_RecordSetStringW(uirow,2,comp->ComponentId);
|
|
|
|
MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2008-01-16 10:11:22 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
2007-10-19 23:21:45 +00:00
|
|
|
}
|
2008-07-08 20:52:29 +00:00
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
CLSID clsid;
|
|
|
|
LPWSTR source;
|
|
|
|
|
|
|
|
LPWSTR path;
|
|
|
|
ITypeLib *ptLib;
|
|
|
|
} typelib_struct;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
|
2006-02-17 00:04:10 +00:00
|
|
|
LPWSTR lpszName, LONG_PTR lParam)
|
|
|
|
{
|
|
|
|
TLIBATTR *attr;
|
|
|
|
typelib_struct *tl_struct = (typelib_struct*) lParam;
|
|
|
|
static const WCHAR fmt[] = {'%','s','\\','%','i',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
int sz;
|
2006-02-17 00:04:10 +00:00
|
|
|
HRESULT res;
|
|
|
|
|
|
|
|
if (!IS_INTRESOURCE(lpszName))
|
|
|
|
{
|
|
|
|
ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sz = strlenW(tl_struct->source)+4;
|
|
|
|
sz *= sizeof(WCHAR);
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
if ((INT_PTR)lpszName == 1)
|
2006-02-17 00:04:10 +00:00
|
|
|
tl_struct->path = strdupW(tl_struct->source);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tl_struct->path = msi_alloc(sz);
|
|
|
|
sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("trying %s\n", debugstr_w(tl_struct->path));
|
|
|
|
res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
|
2008-12-27 15:10:14 +00:00
|
|
|
if (FAILED(res))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
msi_free(tl_struct->path);
|
|
|
|
tl_struct->path = NULL;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
|
|
|
|
if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
|
|
|
|
{
|
|
|
|
ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
msi_free(tl_struct->path);
|
|
|
|
tl_struct->path = NULL;
|
|
|
|
|
|
|
|
ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
|
|
|
|
ITypeLib_Release(tl_struct->ptLib);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE* package = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
LPCWSTR component;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIFILE *file;
|
|
|
|
typelib_struct tl_struct;
|
2008-12-27 15:10:14 +00:00
|
|
|
ITypeLib *tlib;
|
2006-02-17 00:04:10 +00:00
|
|
|
HMODULE module;
|
2008-12-27 15:10:14 +00:00
|
|
|
HRESULT hr;
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
component = MSI_RecordGetString(row,3);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package,component);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
|
|
|
TRACE("component has no key path\n");
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
|
|
|
|
if (module)
|
|
|
|
{
|
|
|
|
LPCWSTR guid;
|
|
|
|
guid = MSI_RecordGetString(row,1);
|
2012-01-21 17:19:12 +00:00
|
|
|
CLSIDFromString( guid, &tl_struct.clsid);
|
2006-02-17 00:04:10 +00:00
|
|
|
tl_struct.source = strdupW( file->TargetPath );
|
|
|
|
tl_struct.path = NULL;
|
|
|
|
|
|
|
|
EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
|
|
|
|
(LONG_PTR)&tl_struct);
|
|
|
|
|
|
|
|
if (tl_struct.path)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
LPCWSTR helpid, help_path = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
HRESULT res;
|
|
|
|
|
|
|
|
helpid = MSI_RecordGetString(row,6);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (helpid) help_path = msi_get_target_folder( package, helpid );
|
|
|
|
res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
if (FAILED(res))
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
|
2006-02-17 00:04:10 +00:00
|
|
|
else
|
|
|
|
TRACE("Registered %s\n", debugstr_w(tl_struct.path));
|
|
|
|
|
|
|
|
ITypeLib_Release(tl_struct.ptLib);
|
|
|
|
msi_free(tl_struct.path);
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
FreeLibrary(module);
|
|
|
|
msi_free(tl_struct.source);
|
|
|
|
}
|
|
|
|
else
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
|
|
|
hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
|
|
|
|
if (FAILED(hr))
|
|
|
|
{
|
|
|
|
ERR("Failed to load type library: %08x\n", hr);
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_INSTALL_FAILURE;
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ITypeLib_Release(tlib);
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','T','y','p','e','L','i','b','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterTypeLibraries);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR component, guid;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
GUID libid;
|
|
|
|
UINT version;
|
|
|
|
LCID language;
|
|
|
|
SYSKIND syskind;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 3 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2010-03-01 12:01:30 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
|
2010-03-01 12:01:30 +00:00
|
|
|
|
|
|
|
guid = MSI_RecordGetString( row, 1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
CLSIDFromString( guid, &libid );
|
2010-03-01 12:01:30 +00:00
|
|
|
version = MSI_RecordGetInteger( row, 4 );
|
|
|
|
language = MSI_RecordGetInteger( row, 2 );
|
|
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
syskind = SYS_WIN64;
|
|
|
|
#else
|
|
|
|
syskind = SYS_WIN32;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
|
|
|
|
if (FAILED(hr))
|
|
|
|
{
|
|
|
|
WARN("Failed to unregister typelib: %08x\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','T','y','p','e','L','i','b','`',0};
|
2010-03-01 12:01:30 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szUnregisterTypeLibraries);
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
|
|
|
|
{
|
|
|
|
static const WCHAR szlnk[] = {'.','l','n','k',0};
|
2012-01-21 17:19:12 +00:00
|
|
|
LPCWSTR directory, extension, link_folder;
|
|
|
|
LPWSTR link_file, filename;
|
2010-03-01 12:01:30 +00:00
|
|
|
|
|
|
|
directory = MSI_RecordGetString( row, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
link_folder = msi_get_target_folder( package, directory );
|
|
|
|
if (!link_folder)
|
|
|
|
{
|
|
|
|
ERR("unable to resolve folder %s\n", debugstr_w(directory));
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-03-01 12:01:30 +00:00
|
|
|
/* may be needed because of a bug somewhere else */
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_create_full_path( link_folder );
|
2010-03-01 12:01:30 +00:00
|
|
|
|
|
|
|
filename = msi_dup_record_field( row, 3 );
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_reduce_to_long_filename( filename );
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2014-04-23 14:48:52 +00:00
|
|
|
extension = strrchrW( filename, '.' );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!extension || strcmpiW( extension, szlnk ))
|
|
|
|
{
|
|
|
|
int len = strlenW( filename );
|
|
|
|
filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
|
|
|
|
memcpy( filename + len, szlnk, sizeof(szlnk) );
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
link_file = msi_build_directory_name( 2, link_folder, filename );
|
2010-03-01 12:01:30 +00:00
|
|
|
msi_free( filename );
|
|
|
|
|
|
|
|
return link_file;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
|
|
|
|
{
|
|
|
|
static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
|
|
|
|
static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
|
|
|
|
WCHAR *folder, *dest, *path;
|
|
|
|
|
|
|
|
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
folder = msi_dup_property( package->db, szWindowsFolder );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
|
|
|
|
folder = msi_build_directory_name( 2, appdata, szMicrosoft );
|
|
|
|
msi_free( appdata );
|
|
|
|
}
|
|
|
|
dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
|
|
|
|
msi_create_full_path( dest );
|
|
|
|
path = msi_build_directory_name( 2, dest, icon_name );
|
|
|
|
msi_free( folder );
|
|
|
|
msi_free( dest );
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2010-03-01 12:01:30 +00:00
|
|
|
LPWSTR link_file, deformated, path;
|
|
|
|
LPCWSTR component, target;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSICOMPONENT *comp;
|
2006-08-01 23:12:11 +00:00
|
|
|
IShellLinkW *sl = NULL;
|
|
|
|
IPersistFile *pf = NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
HRESULT res;
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
component = MSI_RecordGetString(row, 4);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package, component);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
|
|
&IID_IShellLinkW, (LPVOID *) &sl );
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
if (FAILED( res ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
ERR("CLSID_ShellLink not available\n");
|
|
|
|
goto err;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
|
2006-08-01 23:12:11 +00:00
|
|
|
if (FAILED( res ))
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2006-08-01 23:12:11 +00:00
|
|
|
ERR("QueryInterface(IID_IPersistFile) failed\n");
|
|
|
|
goto err;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
target = MSI_RecordGetString(row, 5);
|
|
|
|
if (strchrW(target, '['))
|
2006-08-01 23:12:11 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
deformat_string( package, target, &path );
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("target path is %s\n", debugstr_w(path));
|
|
|
|
IShellLinkW_SetPath( sl, path );
|
|
|
|
msi_free( path );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("poorly handled shortcut format, advertised shortcut\n");
|
2014-09-23 18:32:48 +00:00
|
|
|
path = resolve_keypath( package, comp );
|
|
|
|
IShellLinkW_SetPath( sl, path );
|
|
|
|
msi_free( path );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,6))
|
|
|
|
{
|
2010-03-01 12:01:30 +00:00
|
|
|
LPCWSTR arguments = MSI_RecordGetString(row, 6);
|
|
|
|
deformat_string(package, arguments, &deformated);
|
2006-02-17 00:04:10 +00:00
|
|
|
IShellLinkW_SetArguments(sl,deformated);
|
|
|
|
msi_free(deformated);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,7))
|
|
|
|
{
|
2010-03-01 12:01:30 +00:00
|
|
|
LPCWSTR description = MSI_RecordGetString(row, 7);
|
|
|
|
IShellLinkW_SetDescription(sl, description);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,8))
|
|
|
|
IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,9))
|
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
INT index;
|
2010-03-01 12:01:30 +00:00
|
|
|
LPCWSTR icon = MSI_RecordGetString(row, 9);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
path = msi_build_icon_path(package, icon);
|
2006-02-17 00:04:10 +00:00
|
|
|
index = MSI_RecordGetInteger(row,10);
|
|
|
|
|
2006-08-30 19:24:26 +00:00
|
|
|
/* no value means 0 */
|
|
|
|
if (index == MSI_NULL_INTEGER)
|
|
|
|
index = 0;
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
IShellLinkW_SetIconLocation(sl, path, index);
|
|
|
|
msi_free(path);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,11))
|
|
|
|
IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
|
|
|
|
|
|
|
|
if (!MSI_RecordIsNull(row,12))
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
|
|
|
|
full_path = msi_get_target_folder( package, wkdir );
|
|
|
|
if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2010-03-01 12:01:30 +00:00
|
|
|
link_file = get_link_file(package, row);
|
|
|
|
|
|
|
|
TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
|
|
|
|
IPersistFile_Save(pf, link_file, FALSE);
|
|
|
|
msi_free(link_file);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
err:
|
|
|
|
if (pf)
|
|
|
|
IPersistFile_Release( pf );
|
|
|
|
if (sl)
|
|
|
|
IShellLinkW_Release( sl );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','S','h','o','r','t','c','u','t','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
HRESULT res;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szCreateShortcuts);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
res = CoInitialize( NULL );
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (SUCCEEDED(res)) CoUninitialize();
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPWSTR link_file;
|
|
|
|
LPCWSTR component;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 4 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2010-03-01 12:01:30 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
|
2010-03-01 12:01:30 +00:00
|
|
|
|
|
|
|
link_file = get_link_file( package, row );
|
|
|
|
|
|
|
|
TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
|
|
|
|
if (!DeleteFileW( link_file ))
|
|
|
|
{
|
|
|
|
WARN("Failed to remove shortcut file %u\n", GetLastError());
|
|
|
|
}
|
|
|
|
msi_free( link_file );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','S','h','o','r','t','c','u','t','`',0};
|
2010-03-01 12:01:30 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveShortcuts);
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE* package = param;
|
2006-02-17 00:04:10 +00:00
|
|
|
HANDLE the_file;
|
|
|
|
LPWSTR FilePath;
|
|
|
|
LPCWSTR FileName;
|
|
|
|
CHAR buffer[1024];
|
|
|
|
DWORD sz;
|
|
|
|
UINT rc;
|
|
|
|
|
|
|
|
FileName = MSI_RecordGetString(row,1);
|
|
|
|
if (!FileName)
|
|
|
|
{
|
|
|
|
ERR("Unable to get FileName\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
FilePath = msi_build_icon_path(package, FileName);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
|
|
|
|
|
|
|
|
the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
|
|
if (the_file == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
ERR("Unable to create file %s\n",debugstr_w(FilePath));
|
|
|
|
msi_free(FilePath);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
do
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
DWORD write;
|
|
|
|
sz = 1024;
|
|
|
|
rc = MSI_RecordReadStream(row,2,buffer,&sz);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("Failed to get stream\n");
|
|
|
|
DeleteFileW(FilePath);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
WriteFile(the_file,buffer,sz,&write,NULL);
|
|
|
|
} while (sz == 1024);
|
|
|
|
|
|
|
|
msi_free(FilePath);
|
|
|
|
CloseHandle(the_file);
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
static UINT msi_publish_icons(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
static const WCHAR query[]= {
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','c','o','n','`',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
2008-07-08 20:52:29 +00:00
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW(package->db, query, &view);
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
|
2008-07-08 20:52:29 +00:00
|
|
|
msiobj_release(&view->hdr);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
2008-07-08 20:52:29 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
HKEY source;
|
|
|
|
LPWSTR buffer;
|
|
|
|
MSIMEDIADISK *disk;
|
|
|
|
MSISOURCELISTINFO *info;
|
|
|
|
|
|
|
|
r = RegCreateKeyW(hkey, szSourceList, &source);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
RegCloseKey(source);
|
|
|
|
|
|
|
|
buffer = strrchrW(package->PackagePath, '\\') + 1;
|
|
|
|
r = MsiSourceListSetInfoW(package->ProductCode, NULL,
|
|
|
|
package->Context, MSICODE_PRODUCT,
|
|
|
|
INSTALLPROPERTY_PACKAGENAMEW, buffer);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = MsiSourceListSetInfoW(package->ProductCode, NULL,
|
|
|
|
package->Context, MSICODE_PRODUCT,
|
|
|
|
INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = MsiSourceListSetInfoW(package->ProductCode, NULL,
|
|
|
|
package->Context, MSICODE_PRODUCT,
|
|
|
|
INSTALLPROPERTY_DISKPROMPTW, szEmpty);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
|
|
|
|
{
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_set_last_used_source(package->ProductCode, NULL, info->context,
|
|
|
|
info->options, info->value);
|
|
|
|
else
|
|
|
|
MsiSourceListSetInfoW(package->ProductCode, NULL,
|
|
|
|
info->context, info->options,
|
|
|
|
info->property, info->value);
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
|
|
|
|
{
|
|
|
|
MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
|
|
|
|
disk->context, disk->options,
|
|
|
|
disk->disk_id, disk->volume_label, disk->disk_prompt);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
|
|
|
|
{
|
|
|
|
static const WCHAR szARPProductIcon[] =
|
|
|
|
{'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
|
|
|
|
static const WCHAR szAssignment[] =
|
|
|
|
{'A','s','s','i','g','n','m','e','n','t',0};
|
|
|
|
static const WCHAR szAdvertiseFlags[] =
|
|
|
|
{'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
|
|
|
|
static const WCHAR szClients[] =
|
|
|
|
{'C','l','i','e','n','t','s',0};
|
|
|
|
static const WCHAR szColon[] = {':',0};
|
2022-03-12 22:50:35 +00:00
|
|
|
WCHAR *buffer, *ptr, *guids, packcode[SQUASHED_GUID_SIZE];
|
|
|
|
DWORD langid;
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
|
|
|
|
msi_free(buffer);
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
langid = msi_get_property_int(package->db, szProductLanguage, 0);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
|
|
|
|
|
|
|
|
/* FIXME */
|
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
buffer = msi_dup_property(package->db, szARPProductIcon);
|
2008-07-08 20:52:29 +00:00
|
|
|
if (buffer)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
LPWSTR path = msi_build_icon_path(package, buffer);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
|
|
|
|
msi_free(path);
|
|
|
|
msi_free(buffer);
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
buffer = msi_dup_property(package->db, szProductVersion);
|
2008-07-08 20:52:29 +00:00
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
DWORD verdword = msi_version_str_to_dword(buffer);
|
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
|
|
|
|
msi_free(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
msi_reg_set_val_dword(hkey, szAssignment, 0);
|
|
|
|
msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
|
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
|
|
|
|
msi_reg_set_val_str(hkey, szClients, szColon);
|
|
|
|
|
2022-03-12 22:50:35 +00:00
|
|
|
if (!(guids = msi_get_package_code(package->db))) return ERROR_OUTOFMEMORY;
|
|
|
|
if ((ptr = strchrW(guids, ';'))) *ptr = 0;
|
2008-07-08 20:52:29 +00:00
|
|
|
squash_guid(guids, packcode);
|
2022-03-12 22:50:35 +00:00
|
|
|
msi_free( guids);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
HKEY hkey;
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *upgrade, squashed_pc[SQUASHED_GUID_SIZE];
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
upgrade = msi_dup_property(package->db, szUpgradeCode);
|
2008-07-08 20:52:29 +00:00
|
|
|
if (!upgrade)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
|
|
|
|
else
|
|
|
|
r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WARN("failed to open upgrade code key\n");
|
|
|
|
msi_free(upgrade);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2008-07-08 20:52:29 +00:00
|
|
|
squash_guid(package->ProductCode, squashed_pc);
|
|
|
|
msi_reg_set_val_str(hkey, squashed_pc, NULL);
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
msi_free(upgrade);
|
2012-01-21 17:19:12 +00:00
|
|
|
return ERROR_SUCCESS;
|
2008-07-08 20:52:29 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static BOOL msi_check_publish(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
feature->Action = msi_get_feature_action( package, feature );
|
2018-01-20 11:29:30 +00:00
|
|
|
if (feature->Action == INSTALLSTATE_LOCAL || feature->Action == INSTALLSTATE_SOURCE)
|
2008-01-16 10:11:22 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
static BOOL msi_check_unpublish(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
feature->Action = msi_get_feature_action( package, feature );
|
|
|
|
if (feature->Action != INSTALLSTATE_ABSENT)
|
2008-07-08 20:52:29 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
static UINT msi_publish_patches( MSIPACKAGE *package )
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
|
2008-12-27 15:10:14 +00:00
|
|
|
WCHAR patch_squashed[GUID_SIZE];
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
HKEY patches_key = NULL, product_patches_key = NULL, product_key;
|
2008-12-27 15:10:14 +00:00
|
|
|
LONG res;
|
2010-05-29 08:55:43 +00:00
|
|
|
MSIPATCHINFO *patch;
|
|
|
|
UINT r;
|
|
|
|
WCHAR *p, *all_patches = NULL;
|
|
|
|
DWORD len = 0;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2010-10-22 13:18:11 +00:00
|
|
|
r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
2008-12-27 15:10:14 +00:00
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
|
|
|
|
{
|
|
|
|
squash_guid( patch->patchcode, patch_squashed );
|
|
|
|
len += strlenW( patch_squashed ) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
|
|
|
|
if (!all_patches)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
|
|
|
|
{
|
|
|
|
HKEY patch_key;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
squash_guid( patch->patchcode, p );
|
|
|
|
p += strlenW( p ) + 1;
|
|
|
|
|
|
|
|
res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
|
|
|
|
(const BYTE *)patch->transforms,
|
|
|
|
(strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
|
|
|
|
(strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
|
2010-05-29 08:55:43 +00:00
|
|
|
RegCloseKey( patch_key );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
|
|
|
|
{
|
|
|
|
res = GetLastError();
|
|
|
|
ERR("Unable to copy patch package %d\n", res);
|
|
|
|
goto done;
|
|
|
|
}
|
2010-05-29 08:55:43 +00:00
|
|
|
res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
2017-06-03 22:29:55 +00:00
|
|
|
res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state,
|
|
|
|
sizeof(patch->state) );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
RegCloseKey( patch_key );
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = RegSetValueExW( patch_key, szUninstallable, 0, REG_DWORD, (const BYTE *)&patch->uninstallable,
|
|
|
|
sizeof(patch->uninstallable) );
|
2010-05-29 08:55:43 +00:00
|
|
|
RegCloseKey( patch_key );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
all_patches[len] = 0;
|
|
|
|
res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
|
|
|
|
(const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
|
2008-12-27 15:10:14 +00:00
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
|
|
|
|
(const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
2008-12-27 15:10:14 +00:00
|
|
|
|
|
|
|
done:
|
2010-05-29 08:55:43 +00:00
|
|
|
RegCloseKey( product_patches_key );
|
|
|
|
RegCloseKey( patches_key );
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
RegCloseKey( product_key );
|
2010-05-29 08:55:43 +00:00
|
|
|
msi_free( all_patches );
|
2008-12-27 15:10:14 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ACTION_PublishProduct(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
UINT rc;
|
2010-03-06 09:05:09 +00:00
|
|
|
HKEY hukey = NULL, hudkey = NULL;
|
|
|
|
MSIRECORD *uirow;
|
2022-03-12 15:34:11 +00:00
|
|
|
BOOL republish = FALSE;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szPublishProduct);
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!list_empty(&package->patches))
|
|
|
|
{
|
|
|
|
rc = msi_publish_patches(package);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2022-03-12 15:34:11 +00:00
|
|
|
rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
|
|
|
|
&hukey, FALSE);
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WCHAR *package_code;
|
|
|
|
|
|
|
|
package_code = msi_reg_get_val_str(hukey, INSTALLPROPERTY_PACKAGECODEW);
|
|
|
|
if (package_code)
|
|
|
|
{
|
|
|
|
WCHAR *guid;
|
|
|
|
|
|
|
|
guid = msi_get_package_code(package->db);
|
|
|
|
if (guid)
|
|
|
|
{
|
|
|
|
WCHAR packed[SQUASHED_GUID_SIZE];
|
|
|
|
|
|
|
|
squash_guid(guid, packed);
|
|
|
|
msi_free(guid);
|
|
|
|
if (!strcmpW(packed, package_code))
|
|
|
|
{
|
|
|
|
TRACE("re-publishing product - new package\n");
|
|
|
|
republish = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
msi_free(package_code);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* FIXME: also need to publish if the product is in advertise mode */
|
2022-03-12 15:34:11 +00:00
|
|
|
if (!republish && !msi_check_publish(package))
|
|
|
|
{
|
|
|
|
if (hukey)
|
|
|
|
RegCloseKey(hukey);
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
2022-03-12 15:34:11 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 15:34:11 +00:00
|
|
|
if (!hukey)
|
|
|
|
{
|
|
|
|
rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
|
|
|
|
&hukey, TRUE);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
}
|
2008-05-17 19:46:01 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
|
|
|
|
NULL, &hudkey, TRUE);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
rc = msi_publish_upgrade_code(package);
|
2008-04-04 13:43:40 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
rc = msi_publish_product_properties(package, hukey);
|
2008-04-04 13:43:40 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
rc = msi_publish_sourcelist(package, hukey);
|
2008-04-04 13:43:40 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
rc = msi_publish_icons(package);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
end:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 1 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, package->ProductCode );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
RegCloseKey(hukey);
|
2008-01-16 10:11:22 +00:00
|
|
|
RegCloseKey(hudkey);
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
|
|
|
|
{
|
|
|
|
WCHAR *filename, *ptr, *folder, *ret;
|
|
|
|
const WCHAR *dirprop;
|
|
|
|
|
|
|
|
filename = msi_dup_record_field( row, 2 );
|
|
|
|
if (filename && (ptr = strchrW( filename, '|' )))
|
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
ptr = filename;
|
|
|
|
|
|
|
|
dirprop = MSI_RecordGetString( row, 3 );
|
|
|
|
if (dirprop)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
folder = strdupW( msi_get_target_folder( package, dirprop ) );
|
|
|
|
if (!folder) folder = msi_dup_property( package->db, dirprop );
|
2010-03-06 09:05:09 +00:00
|
|
|
}
|
|
|
|
else
|
2010-05-29 08:55:43 +00:00
|
|
|
folder = msi_dup_property( package->db, szWindowsFolder );
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
if (!folder)
|
|
|
|
{
|
|
|
|
ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
|
|
|
|
msi_free( filename );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
ret = msi_build_directory_name( 2, folder, ptr );
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
msi_free( filename );
|
|
|
|
msi_free( folder );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR component, section, key, value, identifier;
|
|
|
|
LPWSTR deformated_section, deformated_key, deformated_value, fullname;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSIRECORD * uirow;
|
|
|
|
INT action;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString(row, 8);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package,component);
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
identifier = MSI_RecordGetString(row,1);
|
2006-02-17 00:04:10 +00:00
|
|
|
section = MSI_RecordGetString(row,4);
|
|
|
|
key = MSI_RecordGetString(row,5);
|
|
|
|
value = MSI_RecordGetString(row,6);
|
|
|
|
action = MSI_RecordGetInteger(row,7);
|
|
|
|
|
|
|
|
deformat_string(package,section,&deformated_section);
|
|
|
|
deformat_string(package,key,&deformated_key);
|
|
|
|
deformat_string(package,value,&deformated_value);
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
fullname = get_ini_file_name(package, row);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
if (action == 0)
|
|
|
|
{
|
|
|
|
TRACE("Adding value %s to section %s in %s\n",
|
|
|
|
debugstr_w(deformated_key), debugstr_w(deformated_section),
|
|
|
|
debugstr_w(fullname));
|
|
|
|
WritePrivateProfileStringW(deformated_section, deformated_key,
|
|
|
|
deformated_value, fullname);
|
|
|
|
}
|
|
|
|
else if (action == 1)
|
|
|
|
{
|
|
|
|
WCHAR returned[10];
|
|
|
|
GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
|
|
|
|
returned, 10, fullname);
|
|
|
|
if (returned[0] == 0)
|
|
|
|
{
|
|
|
|
TRACE("Adding value %s to section %s in %s\n",
|
|
|
|
debugstr_w(deformated_key), debugstr_w(deformated_section),
|
|
|
|
debugstr_w(fullname));
|
|
|
|
|
|
|
|
WritePrivateProfileStringW(deformated_section, deformated_key,
|
|
|
|
deformated_value, fullname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (action == 3)
|
|
|
|
FIXME("Append to existing section not yet implemented\n");
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord(4);
|
|
|
|
MSI_RecordSetStringW(uirow,1,identifier);
|
|
|
|
MSI_RecordSetStringW(uirow,2,deformated_section);
|
|
|
|
MSI_RecordSetStringW(uirow,3,deformated_key);
|
|
|
|
MSI_RecordSetStringW(uirow,4,deformated_value);
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(fullname);
|
|
|
|
msi_free(deformated_key);
|
|
|
|
msi_free(deformated_value);
|
|
|
|
msi_free(deformated_section);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','n','i','F','i','l','e','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szWriteIniValues);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR component, section, key, value, identifier;
|
|
|
|
LPWSTR deformated_section, deformated_key, deformated_value, filename;
|
|
|
|
MSICOMPONENT *comp;
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIRECORD *uirow;
|
2010-03-06 09:05:09 +00:00
|
|
|
INT action;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
component = MSI_RecordGetString( row, 8 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
identifier = MSI_RecordGetString( row, 1 );
|
|
|
|
section = MSI_RecordGetString( row, 4 );
|
|
|
|
key = MSI_RecordGetString( row, 5 );
|
|
|
|
value = MSI_RecordGetString( row, 6 );
|
|
|
|
action = MSI_RecordGetInteger( row, 7 );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
deformat_string( package, section, &deformated_section );
|
|
|
|
deformat_string( package, key, &deformated_key );
|
|
|
|
deformat_string( package, value, &deformated_value );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
filename = get_ini_file_name( package, row );
|
|
|
|
|
|
|
|
TRACE("Removing key %s from section %s in %s\n",
|
|
|
|
debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
|
|
|
|
|
|
|
|
if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
|
|
|
|
{
|
|
|
|
WARN("Unable to remove key %u\n", GetLastError());
|
|
|
|
}
|
|
|
|
msi_free( filename );
|
2008-12-27 15:10:14 +00:00
|
|
|
}
|
2010-03-06 09:05:09 +00:00
|
|
|
else
|
|
|
|
FIXME("Unsupported action %d\n", action);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 4 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, identifier );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, deformated_section );
|
|
|
|
MSI_RecordSetStringW( uirow, 3, deformated_key );
|
|
|
|
MSI_RecordSetStringW( uirow, 4, deformated_value );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2006-08-01 23:12:11 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
msi_free( deformated_key );
|
|
|
|
msi_free( deformated_value );
|
|
|
|
msi_free( deformated_section );
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR component, section, key, value, identifier;
|
|
|
|
LPWSTR deformated_section, deformated_key, deformated_value, filename;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
INT action;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( row, 8 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2010-03-06 09:05:09 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
identifier = MSI_RecordGetString( row, 1 );
|
|
|
|
section = MSI_RecordGetString( row, 4 );
|
|
|
|
key = MSI_RecordGetString( row, 5 );
|
|
|
|
value = MSI_RecordGetString( row, 6 );
|
|
|
|
action = MSI_RecordGetInteger( row, 7 );
|
|
|
|
|
|
|
|
deformat_string( package, section, &deformated_section );
|
|
|
|
deformat_string( package, key, &deformated_key );
|
|
|
|
deformat_string( package, value, &deformated_value );
|
|
|
|
|
|
|
|
if (action == msidbIniFileActionRemoveLine)
|
|
|
|
{
|
|
|
|
filename = get_ini_file_name( package, row );
|
|
|
|
|
|
|
|
TRACE("Removing key %s from section %s in %s\n",
|
|
|
|
debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
|
|
|
|
|
|
|
|
if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
|
|
|
|
{
|
|
|
|
WARN("Unable to remove key %u\n", GetLastError());
|
|
|
|
}
|
|
|
|
msi_free( filename );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
FIXME("Unsupported action %d\n", action);
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 4 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, identifier );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, deformated_section );
|
|
|
|
MSI_RecordSetStringW( uirow, 3, deformated_key );
|
|
|
|
MSI_RecordSetStringW( uirow, 4, deformated_value );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free( deformated_key );
|
|
|
|
msi_free( deformated_value );
|
|
|
|
msi_free( deformated_section );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','n','i','F','i','l','e','`',0};
|
|
|
|
static const WCHAR remove_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2010-03-06 09:05:09 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveIniValues);
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
static void register_dll( const WCHAR *dll, BOOL unregister )
|
|
|
|
{
|
2017-10-09 11:32:09 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
static const WCHAR regW[] =
|
|
|
|
{'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ','\"','%','s','\"',0};
|
|
|
|
static const WCHAR unregW[] =
|
|
|
|
{'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ','/','u',' ','\"','%','s','\"',0};
|
|
|
|
#else /* __REACTOS__ */
|
2012-12-09 19:43:59 +00:00
|
|
|
static const WCHAR regW[] =
|
|
|
|
{'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"','%','s','\"',0};
|
|
|
|
static const WCHAR unregW[] =
|
|
|
|
{'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"','%','s','\"',0};
|
2017-10-09 11:32:09 +00:00
|
|
|
#endif /* __REACTOS__ */
|
2012-12-09 19:43:59 +00:00
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
STARTUPINFOW si;
|
|
|
|
WCHAR *cmd;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
if (!(cmd = msi_alloc( strlenW(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
if (unregister) sprintfW( cmd, unregW, dll );
|
|
|
|
else sprintfW( cmd, regW, dll );
|
|
|
|
|
|
|
|
memset( &si, 0, sizeof(STARTUPINFOW) );
|
|
|
|
if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
|
|
|
|
{
|
|
|
|
CloseHandle( pi.hThread );
|
|
|
|
msi_dialog_check_messages( pi.hProcess );
|
|
|
|
CloseHandle( pi.hProcess );
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_free( cmd );
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR filename;
|
|
|
|
MSIFILE *file;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
filename = MSI_RecordGetString( row, 1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
file = msi_get_loaded_file( package, filename );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!file)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
WARN("unable to find file %s\n", debugstr_w(filename));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
file->Component->Action = msi_get_component_action( package, file->Component );
|
|
|
|
if (file->Component->Action != INSTALLSTATE_LOCAL)
|
|
|
|
{
|
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
|
2010-03-06 09:05:09 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
|
|
|
|
register_dll( file->TargetPath, FALSE );
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
2012-05-14 21:41:31 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 1, file->File );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','S','e','l','f','R','e','g','`',0};
|
|
|
|
MSIQUERY *view;
|
2010-03-06 09:05:09 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szSelfRegModules);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2010-03-06 09:05:09 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
|
2006-02-17 00:04:10 +00:00
|
|
|
msiobj_release(&view->hdr);
|
2012-01-21 17:19:12 +00:00
|
|
|
return rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR filename;
|
|
|
|
MSIFILE *file;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
|
|
|
|
filename = MSI_RecordGetString( row, 1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
file = msi_get_loaded_file( package, filename );
|
2010-02-06 21:28:28 +00:00
|
|
|
if (!file)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
WARN("unable to find file %s\n", debugstr_w(filename));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
file->Component->Action = msi_get_component_action( package, file->Component );
|
|
|
|
if (file->Component->Action != INSTALLSTATE_ABSENT)
|
|
|
|
{
|
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
|
2010-02-06 21:28:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
|
|
|
|
register_dll( file->TargetPath, TRUE );
|
2010-02-06 21:28:28 +00:00
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
2012-05-14 21:41:31 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 1, file->File );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-02-06 21:28:28 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','S','e','l','f','R','e','g','`',0};
|
2010-02-06 21:28:28 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2010-02-06 21:28:28 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szSelfUnregModules);
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
|
2010-02-06 21:28:28 +00:00
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
return rc;
|
2010-02-06 21:28:28 +00:00
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
UINT rc;
|
2010-03-06 09:05:09 +00:00
|
|
|
HKEY hkey = NULL, userdata = NULL;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szPublishFeatures);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!msi_check_publish(package))
|
|
|
|
return ERROR_SUCCESS;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
rc = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
|
2008-12-27 15:10:14 +00:00
|
|
|
&hkey, TRUE);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
|
2008-12-27 15:10:14 +00:00
|
|
|
&userdata, TRUE);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/* here the guids are base 85 encoded */
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
|
|
|
ComponentList *cl;
|
|
|
|
LPWSTR data = NULL;
|
|
|
|
GUID clsid;
|
|
|
|
INT size;
|
|
|
|
BOOL absent = FALSE;
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIRECORD *uirow;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2014-09-23 18:32:48 +00:00
|
|
|
if (feature->Level <= 0) continue;
|
2022-03-12 14:11:50 +00:00
|
|
|
if (feature->Action == INSTALLSTATE_UNKNOWN &&
|
|
|
|
feature->Installed != INSTALLSTATE_ABSENT) continue;
|
2014-09-23 18:32:48 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (feature->Action != INSTALLSTATE_LOCAL &&
|
|
|
|
feature->Action != INSTALLSTATE_SOURCE &&
|
|
|
|
feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
size = 1;
|
|
|
|
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
|
|
|
|
{
|
|
|
|
size += 21;
|
|
|
|
}
|
|
|
|
if (feature->Feature_Parent)
|
|
|
|
size += strlenW( feature->Feature_Parent )+2;
|
|
|
|
|
|
|
|
data = msi_alloc(size * sizeof(WCHAR));
|
|
|
|
|
|
|
|
data[0] = 0;
|
|
|
|
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
|
|
|
|
{
|
|
|
|
MSICOMPONENT* component = cl->component;
|
|
|
|
WCHAR buf[21];
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
buf[0] = 0;
|
2006-02-17 00:04:10 +00:00
|
|
|
if (component->ComponentId)
|
|
|
|
{
|
|
|
|
TRACE("From %s\n",debugstr_w(component->ComponentId));
|
|
|
|
CLSIDFromString(component->ComponentId, &clsid);
|
|
|
|
encode_base85_guid(&clsid,buf);
|
|
|
|
TRACE("to %s\n",debugstr_w(buf));
|
|
|
|
strcatW(data,buf);
|
|
|
|
}
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
if (feature->Feature_Parent)
|
|
|
|
{
|
|
|
|
static const WCHAR sep[] = {'\2',0};
|
|
|
|
strcatW(data,sep);
|
|
|
|
strcatW(data,feature->Feature_Parent);
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_reg_set_val_str( userdata, feature->Feature, data );
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(data);
|
|
|
|
|
|
|
|
size = 0;
|
|
|
|
if (feature->Feature_Parent)
|
|
|
|
size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
|
|
|
|
if (!absent)
|
|
|
|
{
|
2008-05-17 19:46:01 +00:00
|
|
|
size += sizeof(WCHAR);
|
2008-07-08 20:52:29 +00:00
|
|
|
RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
|
2010-05-29 08:55:43 +00:00
|
|
|
(const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size += 2*sizeof(WCHAR);
|
|
|
|
data = msi_alloc(size);
|
|
|
|
data[0] = 0x6;
|
|
|
|
data[1] = 0;
|
|
|
|
if (feature->Feature_Parent)
|
|
|
|
strcpyW( &data[1], feature->Feature_Parent );
|
2008-07-08 20:52:29 +00:00
|
|
|
RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
|
2006-02-17 00:04:10 +00:00
|
|
|
(LPBYTE)data,size);
|
|
|
|
msi_free(data);
|
|
|
|
}
|
2006-08-01 23:12:11 +00:00
|
|
|
|
|
|
|
/* the UI chunk */
|
|
|
|
uirow = MSI_CreateRecord( 1 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, feature->Feature );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2006-08-01 23:12:11 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
/* FIXME: call msi_ui_progress? */
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
RegCloseKey(hkey);
|
2008-07-08 20:52:29 +00:00
|
|
|
RegCloseKey(userdata);
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
HKEY hkey;
|
2010-05-29 08:55:43 +00:00
|
|
|
MSIRECORD *uirow;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
|
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
r = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
|
2008-12-27 15:10:14 +00:00
|
|
|
&hkey, FALSE);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
RegDeleteValueW(hkey, feature->Feature);
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
}
|
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
|
2008-12-27 15:10:14 +00:00
|
|
|
&hkey, FALSE);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
RegDeleteValueW(hkey, feature->Feature);
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
uirow = MSI_CreateRecord( 1 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, feature->Feature );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-05-29 08:55:43 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szUnpublishFeatures);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!msi_check_unpublish(package))
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
|
|
|
|
{
|
|
|
|
msi_unpublish_feature(package, feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-07-08 20:52:29 +00:00
|
|
|
SYSTEMTIME systime;
|
|
|
|
DWORD size, langid;
|
2010-05-29 08:55:43 +00:00
|
|
|
WCHAR date[9], *val, *buffer;
|
|
|
|
const WCHAR *prop, *key;
|
2008-07-08 20:52:29 +00:00
|
|
|
|
|
|
|
static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
|
|
|
|
static const WCHAR modpath_fmt[] =
|
|
|
|
{'M','s','i','E','x','e','c','.','e','x','e',' ',
|
|
|
|
'/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
|
|
|
|
static const WCHAR szModifyPath[] =
|
|
|
|
{'M','o','d','i','f','y','P','a','t','h',0};
|
|
|
|
static const WCHAR szUninstallString[] =
|
|
|
|
{'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
|
|
|
|
static const WCHAR szEstimatedSize[] =
|
|
|
|
{'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
|
2010-05-29 08:55:43 +00:00
|
|
|
static const WCHAR szDisplayVersion[] =
|
|
|
|
{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
|
|
|
|
static const WCHAR szInstallSource[] =
|
|
|
|
{'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
|
|
|
|
static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
|
|
|
|
{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
|
|
|
|
static const WCHAR szAuthorizedCDFPrefix[] =
|
|
|
|
{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
|
|
|
|
static const WCHAR szARPCONTACT[] =
|
|
|
|
{'A','R','P','C','O','N','T','A','C','T',0};
|
|
|
|
static const WCHAR szContact[] =
|
|
|
|
{'C','o','n','t','a','c','t',0};
|
|
|
|
static const WCHAR szARPCOMMENTS[] =
|
|
|
|
{'A','R','P','C','O','M','M','E','N','T','S',0};
|
|
|
|
static const WCHAR szComments[] =
|
|
|
|
{'C','o','m','m','e','n','t','s',0};
|
2008-07-08 20:52:29 +00:00
|
|
|
static const WCHAR szProductName[] =
|
|
|
|
{'P','r','o','d','u','c','t','N','a','m','e',0};
|
|
|
|
static const WCHAR szDisplayName[] =
|
|
|
|
{'D','i','s','p','l','a','y','N','a','m','e',0};
|
2010-05-29 08:55:43 +00:00
|
|
|
static const WCHAR szARPHELPLINK[] =
|
|
|
|
{'A','R','P','H','E','L','P','L','I','N','K',0};
|
|
|
|
static const WCHAR szHelpLink[] =
|
|
|
|
{'H','e','l','p','L','i','n','k',0};
|
|
|
|
static const WCHAR szARPHELPTELEPHONE[] =
|
|
|
|
{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
|
|
|
|
static const WCHAR szHelpTelephone[] =
|
|
|
|
{'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
|
|
|
|
static const WCHAR szARPINSTALLLOCATION[] =
|
|
|
|
{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
|
2008-07-08 20:52:29 +00:00
|
|
|
static const WCHAR szManufacturer[] =
|
|
|
|
{'M','a','n','u','f','a','c','t','u','r','e','r',0};
|
2010-05-29 08:55:43 +00:00
|
|
|
static const WCHAR szPublisher[] =
|
|
|
|
{'P','u','b','l','i','s','h','e','r',0};
|
|
|
|
static const WCHAR szARPREADME[] =
|
|
|
|
{'A','R','P','R','E','A','D','M','E',0};
|
|
|
|
static const WCHAR szReadme[] =
|
|
|
|
{'R','e','a','d','M','e',0};
|
|
|
|
static const WCHAR szARPSIZE[] =
|
|
|
|
{'A','R','P','S','I','Z','E',0};
|
|
|
|
static const WCHAR szSize[] =
|
|
|
|
{'S','i','z','e',0};
|
|
|
|
static const WCHAR szARPURLINFOABOUT[] =
|
|
|
|
{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
|
|
|
|
static const WCHAR szURLInfoAbout[] =
|
|
|
|
{'U','R','L','I','n','f','o','A','b','o','u','t',0};
|
|
|
|
static const WCHAR szARPURLUPDATEINFO[] =
|
|
|
|
{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
|
|
|
|
static const WCHAR szURLUpdateInfo[] =
|
|
|
|
{'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR szARPSYSTEMCOMPONENT[] =
|
|
|
|
{'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
|
|
|
|
static const WCHAR szSystemComponent[] =
|
|
|
|
{'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
|
2010-05-29 08:55:43 +00:00
|
|
|
|
|
|
|
static const WCHAR *propval[] = {
|
|
|
|
szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
|
|
|
|
szARPCONTACT, szContact,
|
|
|
|
szARPCOMMENTS, szComments,
|
|
|
|
szProductName, szDisplayName,
|
|
|
|
szARPHELPLINK, szHelpLink,
|
|
|
|
szARPHELPTELEPHONE, szHelpTelephone,
|
|
|
|
szARPINSTALLLOCATION, szInstallLocation,
|
2012-01-21 17:19:12 +00:00
|
|
|
szSourceDir, szInstallSource,
|
2010-05-29 08:55:43 +00:00
|
|
|
szManufacturer, szPublisher,
|
|
|
|
szARPREADME, szReadme,
|
|
|
|
szARPSIZE, szSize,
|
|
|
|
szARPURLINFOABOUT, szURLInfoAbout,
|
|
|
|
szARPURLUPDATEINFO, szURLUpdateInfo,
|
|
|
|
NULL
|
2006-02-17 00:04:10 +00:00
|
|
|
};
|
2010-05-29 08:55:43 +00:00
|
|
|
const WCHAR **p = propval;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
while (*p)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
prop = *p++;
|
|
|
|
key = *p++;
|
|
|
|
val = msi_dup_property(package->db, prop);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_str(hkey, key, val);
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(val);
|
|
|
|
}
|
2008-07-08 20:52:29 +00:00
|
|
|
|
|
|
|
msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
|
|
|
|
{
|
|
|
|
msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
|
|
|
|
}
|
2012-12-09 19:43:59 +00:00
|
|
|
size = deformat_string(package, modpath_fmt, &buffer) * sizeof(WCHAR);
|
2008-07-08 20:52:29 +00:00
|
|
|
RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
|
|
|
|
RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
|
|
|
|
msi_free(buffer);
|
|
|
|
|
|
|
|
/* FIXME: Write real Estimated Size when we have it */
|
|
|
|
msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
|
|
|
|
|
|
|
|
GetLocalTime(&systime);
|
|
|
|
sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
|
|
|
|
msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
langid = msi_get_property_int(package->db, szProductLanguage, 0);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
buffer = msi_dup_property(package->db, szProductVersion);
|
2008-07-08 20:52:29 +00:00
|
|
|
msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
|
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
DWORD verdword = msi_version_str_to_dword(buffer);
|
|
|
|
|
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
|
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
|
|
|
|
msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
|
|
|
|
msi_free(buffer);
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *upgrade_code, squashed_pc[SQUASHED_GUID_SIZE];
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2012-01-21 17:19:12 +00:00
|
|
|
HKEY hkey, props, upgrade_key;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterProduct);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* FIXME: also need to publish if the product is in advertise mode */
|
2022-03-12 15:34:11 +00:00
|
|
|
if (!msi_get_property_int( package->db, szProductToBeRegistered, 0 )
|
|
|
|
&& !msi_check_publish(package))
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
|
2008-12-27 15:10:14 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto done;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
rc = msi_publish_install_properties(package, hkey);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto done;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
rc = msi_publish_install_properties(package, props);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto done;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
upgrade_code = msi_dup_property(package->db, szUpgradeCode);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (upgrade_code)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
squash_guid( package->ProductCode, squashed_pc );
|
|
|
|
msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
|
|
|
|
RegCloseKey( upgrade_key );
|
|
|
|
}
|
|
|
|
msi_free( upgrade_code );
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
|
|
|
|
package->delete_on_close = FALSE;
|
2008-05-17 19:46:01 +00:00
|
|
|
|
2008-07-08 20:52:29 +00:00
|
|
|
done:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 1 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, package->ProductCode );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
RegCloseKey(hkey);
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_InstallExecute(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
return execute_script(package, SCRIPT_INSTALL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
const WCHAR *icon = MSI_RecordGetString( row, 1 );
|
|
|
|
WCHAR *p, *icon_path;
|
|
|
|
|
|
|
|
if (!icon) return ERROR_SUCCESS;
|
|
|
|
if ((icon_path = msi_build_icon_path( package, icon )))
|
|
|
|
{
|
|
|
|
TRACE("removing icon file %s\n", debugstr_w(icon_path));
|
|
|
|
DeleteFileW( icon_path );
|
|
|
|
if ((p = strrchrW( icon_path, '\\' )))
|
|
|
|
{
|
|
|
|
*p = 0;
|
|
|
|
RemoveDirectoryW( icon_path );
|
|
|
|
}
|
|
|
|
msi_free( icon_path );
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT msi_unpublish_icons( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR query[]= {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
static void remove_product_upgrade_code( MSIPACKAGE *package )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR *code, product[SQUASHED_GUID_SIZE];
|
|
|
|
HKEY hkey;
|
|
|
|
LONG res;
|
|
|
|
DWORD count;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
squash_guid( package->ProductCode, product );
|
|
|
|
if (!(code = msi_dup_property( package->db, szUpgradeCode )))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
WARN( "upgrade code not found\n" );
|
|
|
|
return;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
2016-11-22 12:25:27 +00:00
|
|
|
if (!MSIREG_OpenUpgradeCodesKey( code, &hkey, FALSE ))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
RegDeleteValueW( hkey, product );
|
|
|
|
res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
if (!res && !count) MSIREG_DeleteUpgradeCodesKey( code );
|
|
|
|
}
|
|
|
|
if (!MSIREG_OpenUserUpgradeCodesKey( code, &hkey, FALSE ))
|
|
|
|
{
|
|
|
|
RegDeleteValueW( hkey, product );
|
|
|
|
res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
if (!res && !count) MSIREG_DeleteUserUpgradeCodesKey( code );
|
|
|
|
}
|
|
|
|
if (!MSIREG_OpenClassesUpgradeCodesKey( code, &hkey, FALSE ))
|
|
|
|
{
|
|
|
|
RegDeleteValueW( hkey, product );
|
|
|
|
res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
if (!res && !count) MSIREG_DeleteClassesUpgradeCodesKey( code );
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
msi_free( code );
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_UnpublishProduct(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
MSIPATCHINFO *patch;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
MSIREG_DeleteProductKey(package->ProductCode);
|
2016-11-22 12:25:27 +00:00
|
|
|
MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
|
2012-01-21 17:19:12 +00:00
|
|
|
MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
|
|
|
|
MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
|
|
|
|
MSIREG_DeleteUserProductKey(package->ProductCode);
|
|
|
|
MSIREG_DeleteUserFeaturesKey(package->ProductCode);
|
2008-12-27 15:10:14 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
remove_product_upgrade_code( package );
|
2008-07-08 20:52:29 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
|
|
|
|
{
|
|
|
|
MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!strcmpW( package->ProductCode, patch->products ))
|
|
|
|
{
|
|
|
|
TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
|
|
|
|
patch->delete_on_close = TRUE;
|
|
|
|
}
|
|
|
|
/* FIXME: remove local patch package if this is the last product */
|
2010-05-29 08:55:43 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("removing local package %s\n", debugstr_w(package->localfile));
|
|
|
|
package->delete_on_close = TRUE;
|
2010-05-29 08:55:43 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_unpublish_icons( package );
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
static BOOL is_full_uninstall( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
MSIFEATURE *feature;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
if (feature->Action != INSTALLSTATE_ABSENT &&
|
|
|
|
(feature->Installed != INSTALLSTATE_ABSENT || feature->Action != INSTALLSTATE_UNKNOWN))
|
|
|
|
return FALSE;
|
2016-11-22 12:25:27 +00:00
|
|
|
}
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
return TRUE;
|
2016-11-22 12:25:27 +00:00
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/* first do the same as an InstallExecute */
|
2015-03-09 20:28:19 +00:00
|
|
|
rc = execute_script(package, SCRIPT_INSTALL);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
/* then handle commit actions */
|
|
|
|
rc = execute_script(package, SCRIPT_COMMIT);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
if (is_full_uninstall(package))
|
|
|
|
rc = ACTION_UnpublishProduct(package);
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT ACTION_ForceReboot(MSIPACKAGE *package)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
static const WCHAR RunOnce[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\',
|
|
|
|
'M','i','c','r','o','s','o','f','t','\\',
|
|
|
|
'W','i','n','d','o','w','s','\\',
|
|
|
|
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
|
|
|
'R','u','n','O','n','c','e',0};
|
|
|
|
static const WCHAR InstallRunOnce[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\',
|
|
|
|
'M','i','c','r','o','s','o','f','t','\\',
|
|
|
|
'W','i','n','d','o','w','s','\\',
|
|
|
|
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\',
|
|
|
|
'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
|
|
|
|
|
|
|
|
static const WCHAR msiexec_fmt[] = {
|
|
|
|
'%','s',
|
|
|
|
'\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
|
|
|
|
'\"','%','s','\"',0};
|
|
|
|
static const WCHAR install_fmt[] = {
|
|
|
|
'/','I',' ','\"','%','s','\"',' ',
|
|
|
|
'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
|
|
|
|
'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
|
2016-11-22 12:25:27 +00:00
|
|
|
WCHAR buffer[256], sysdir[MAX_PATH], squashed_pc[SQUASHED_GUID_SIZE];
|
2006-02-17 00:04:10 +00:00
|
|
|
HKEY hkey;
|
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
squash_guid( package->ProductCode, squashed_pc );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2022-03-12 22:54:36 +00:00
|
|
|
GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
|
2006-02-17 00:04:10 +00:00
|
|
|
RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
|
2022-03-12 22:54:36 +00:00
|
|
|
snprintfW(buffer, ARRAY_SIZE(buffer), msiexec_fmt, sysdir, squashed_pc);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
msi_reg_set_val_str( hkey, squashed_pc, buffer );
|
2006-02-17 00:04:10 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
|
|
TRACE("Reboot command %s\n",debugstr_w(buffer));
|
|
|
|
|
|
|
|
RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
|
2016-11-22 12:25:27 +00:00
|
|
|
sprintfW( buffer, install_fmt, package->ProductCode, squashed_pc );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2016-11-22 12:25:27 +00:00
|
|
|
msi_reg_set_val_str( hkey, squashed_pc, buffer );
|
2006-02-17 00:04:10 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
|
|
return ERROR_INSTALL_SUSPEND;
|
|
|
|
}
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
static UINT ACTION_ResolveSource(MSIPACKAGE* package)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
DWORD attrib;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
/*
|
2008-01-16 10:11:22 +00:00
|
|
|
* We are currently doing what should be done here in the top level Install
|
|
|
|
* however for Administrative and uninstalls this step will be needed
|
2006-02-17 00:04:10 +00:00
|
|
|
*/
|
|
|
|
if (!package->PackagePath)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_set_sourcedir_props(package, TRUE);
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
attrib = GetFileAttributesW(package->db->path);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (attrib == INVALID_FILE_ATTRIBUTES)
|
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
MSIRECORD *record;
|
|
|
|
LPWSTR prompt;
|
2006-02-17 00:04:10 +00:00
|
|
|
DWORD size = 0;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
|
2008-05-17 19:46:01 +00:00
|
|
|
package->Context, MSICODE_PRODUCT,
|
2006-02-17 00:04:10 +00:00
|
|
|
INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
|
|
|
|
if (rc == ERROR_MORE_DATA)
|
|
|
|
{
|
|
|
|
prompt = msi_alloc(size * sizeof(WCHAR));
|
2008-01-16 10:11:22 +00:00
|
|
|
MsiSourceListGetInfoW(package->ProductCode, NULL,
|
2008-05-17 19:46:01 +00:00
|
|
|
package->Context, MSICODE_PRODUCT,
|
2006-02-17 00:04:10 +00:00
|
|
|
INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
|
|
|
|
}
|
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
prompt = strdupW(package->db->path);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
record = MSI_CreateRecord(2);
|
|
|
|
MSI_RecordSetInteger(record, 1, MSIERR_INSERTDISK);
|
|
|
|
MSI_RecordSetStringW(record, 2, prompt);
|
2012-01-21 17:19:12 +00:00
|
|
|
msi_free(prompt);
|
2006-02-17 00:04:10 +00:00
|
|
|
while(attrib == INVALID_FILE_ATTRIBUTES)
|
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_RecordSetStringW(record, 0, NULL);
|
|
|
|
rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ERROR, record);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc == IDCANCEL)
|
2012-01-21 17:19:12 +00:00
|
|
|
return ERROR_INSTALL_USEREXIT;
|
2008-01-16 10:11:22 +00:00
|
|
|
attrib = GetFileAttributesW(package->db->path);
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RegisterUser(MSIPACKAGE *package)
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
HKEY hkey = 0;
|
|
|
|
LPWSTR buffer, productid = NULL;
|
|
|
|
UINT i, rc = ERROR_SUCCESS;
|
|
|
|
MSIRECORD *uirow;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szPropKeys[][80] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
{'P','r','o','d','u','c','t','I','D',0},
|
|
|
|
{'U','S','E','R','N','A','M','E',0},
|
|
|
|
{'C','O','M','P','A','N','Y','N','A','M','E',0},
|
|
|
|
{0},
|
|
|
|
};
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR szRegKeys[][80] =
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
|
|
|
{'P','r','o','d','u','c','t','I','D',0},
|
|
|
|
{'R','e','g','O','w','n','e','r',0},
|
|
|
|
{'R','e','g','C','o','m','p','a','n','y',0},
|
|
|
|
{0},
|
|
|
|
};
|
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRegisterUser);
|
|
|
|
|
2008-04-04 13:43:40 +00:00
|
|
|
if (msi_check_unpublish(package))
|
|
|
|
{
|
2016-11-22 12:25:27 +00:00
|
|
|
MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
|
2010-03-06 09:05:09 +00:00
|
|
|
goto end;
|
2008-04-04 13:43:40 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (!productid)
|
2010-03-06 09:05:09 +00:00
|
|
|
goto end;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-12-27 15:10:14 +00:00
|
|
|
rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
|
|
|
|
NULL, &hkey, TRUE);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
for( i = 0; szPropKeys[i][0]; i++ )
|
|
|
|
{
|
2010-05-29 08:55:43 +00:00
|
|
|
buffer = msi_dup_property( package->db, szPropKeys[i] );
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
|
|
|
|
msi_free( buffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 1 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, productid );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
msi_free(productid);
|
|
|
|
RegCloseKey(hkey);
|
2008-04-04 13:43:40 +00:00
|
|
|
return rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
static UINT iterate_properties(MSIRECORD *record, void *param)
|
|
|
|
{
|
|
|
|
static const WCHAR prop_template[] =
|
|
|
|
{'P','r','o','p','e','r','t','y','(','S',')',':',' ','[','1',']',' ','=',' ','[','2',']',0};
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
|
|
|
|
uirow = MSI_CloneRecord(record);
|
|
|
|
if (!uirow) return ERROR_OUTOFMEMORY;
|
|
|
|
MSI_RecordSetStringW(uirow, 0, prop_template);
|
|
|
|
MSI_ProcessMessage(param, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow);
|
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
|
|
|
|
{
|
2018-01-20 11:29:30 +00:00
|
|
|
static const WCHAR prop_query[] =
|
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','_','P','r','o','p','e','r','t','y','`',0};
|
|
|
|
WCHAR *productname;
|
|
|
|
WCHAR *action;
|
|
|
|
WCHAR *info_template;
|
|
|
|
MSIQUERY *view;
|
|
|
|
MSIRECORD *uirow, *uirow_info;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
/* Send COMMONDATA and INFO messages. */
|
|
|
|
/* FIXME: when should these messages be sent? [see also MsiOpenPackage()] */
|
|
|
|
uirow = MSI_CreateRecord(3);
|
|
|
|
if (!uirow) return ERROR_OUTOFMEMORY;
|
|
|
|
MSI_RecordSetStringW(uirow, 0, NULL);
|
|
|
|
MSI_RecordSetInteger(uirow, 1, 0);
|
|
|
|
MSI_RecordSetInteger(uirow, 2, package->num_langids ? package->langids[0] : 0);
|
|
|
|
MSI_RecordSetInteger(uirow, 3, msi_get_string_table_codepage(package->db->strings));
|
|
|
|
MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
|
|
|
|
/* FIXME: send INSTALLMESSAGE_PROGRESS */
|
|
|
|
MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
|
|
|
|
|
|
|
|
if (!(needs_ui_sequence(package) && ui_sequence_exists(package)))
|
|
|
|
{
|
|
|
|
uirow_info = MSI_CreateRecord(0);
|
|
|
|
if (!uirow_info)
|
|
|
|
{
|
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
|
|
|
|
MSI_RecordSetStringW(uirow_info, 0, info_template);
|
|
|
|
msi_free(info_template);
|
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow_info);
|
|
|
|
msiobj_release(&uirow_info->hdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow);
|
|
|
|
|
|
|
|
productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
|
|
|
|
MSI_RecordSetInteger(uirow, 1, 1);
|
|
|
|
MSI_RecordSetStringW(uirow, 2, productname);
|
|
|
|
MSI_RecordSetStringW(uirow, 3, NULL);
|
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow);
|
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
|
|
|
|
package->LastActionResult = MSI_NULL_INTEGER;
|
|
|
|
|
|
|
|
action = msi_dup_property(package->db, szEXECUTEACTION);
|
|
|
|
if (!action) action = msi_strdupW(szINSTALL, strlenW(szINSTALL));
|
|
|
|
|
|
|
|
/* Perform the action. Top-level actions trigger a sequence. */
|
|
|
|
if (!strcmpW(action, szINSTALL))
|
|
|
|
{
|
|
|
|
/* Send ACTIONSTART/INFO and INSTALLSTART. */
|
|
|
|
ui_actionstart(package, szINSTALL, NULL, NULL);
|
|
|
|
ui_actioninfo(package, szINSTALL, TRUE, 0);
|
|
|
|
uirow = MSI_CreateRecord(2);
|
|
|
|
if (!uirow)
|
|
|
|
{
|
|
|
|
rc = ERROR_OUTOFMEMORY;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
MSI_RecordSetStringW(uirow, 0, NULL);
|
|
|
|
MSI_RecordSetStringW(uirow, 1, productname);
|
|
|
|
MSI_RecordSetStringW(uirow, 2, package->ProductCode);
|
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLSTART, uirow);
|
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
|
|
|
|
/* Perform the installation. Always use the ExecuteSequence. */
|
|
|
|
package->InWhatSequence |= SEQUENCE_EXEC;
|
|
|
|
rc = ACTION_ProcessExecSequence(package);
|
|
|
|
|
|
|
|
/* Send return value and INSTALLEND. */
|
|
|
|
ui_actioninfo(package, szINSTALL, FALSE, !rc);
|
|
|
|
uirow = MSI_CreateRecord(3);
|
|
|
|
if (!uirow)
|
|
|
|
{
|
|
|
|
rc = ERROR_OUTOFMEMORY;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
MSI_RecordSetStringW(uirow, 0, NULL);
|
|
|
|
MSI_RecordSetStringW(uirow, 1, productname);
|
|
|
|
MSI_RecordSetStringW(uirow, 2, package->ProductCode);
|
|
|
|
MSI_RecordSetInteger(uirow, 3, !rc);
|
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLEND, uirow);
|
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
}
|
|
|
|
else
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_PerformAction(package, action);
|
2018-01-20 11:29:30 +00:00
|
|
|
|
|
|
|
/* Send all set properties. */
|
|
|
|
if (!MSI_OpenQuery(package->db, &view, prop_query))
|
|
|
|
{
|
|
|
|
MSI_IterateRecords(view, NULL, iterate_properties, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And finally, toggle the cancel off and on. */
|
|
|
|
uirow = MSI_CreateRecord(2);
|
|
|
|
if (!uirow)
|
|
|
|
{
|
|
|
|
rc = ERROR_OUTOFMEMORY;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
MSI_RecordSetStringW(uirow, 0, NULL);
|
|
|
|
MSI_RecordSetInteger(uirow, 1, 2);
|
|
|
|
MSI_RecordSetInteger(uirow, 2, 0);
|
|
|
|
MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
|
|
|
|
MSI_RecordSetInteger(uirow, 2, 1);
|
|
|
|
MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
|
|
|
|
msiobj_release(&uirow->hdr);
|
|
|
|
|
|
|
|
end:
|
|
|
|
msi_free(productname);
|
|
|
|
msi_free(action);
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
static UINT ACTION_INSTALL(MSIPACKAGE *package)
|
|
|
|
{
|
|
|
|
msi_set_property(package->db, szEXECUTEACTION, szINSTALL, -1);
|
|
|
|
if (needs_ui_sequence(package) && ui_sequence_exists(package))
|
|
|
|
{
|
|
|
|
package->InWhatSequence |= SEQUENCE_UI;
|
|
|
|
return ACTION_ProcessUISequence(package);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return ACTION_ExecuteAction(package);
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
|
|
|
|
{
|
|
|
|
static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
|
|
|
|
WCHAR productid_85[21], component_85[21], *ret;
|
|
|
|
GUID clsid;
|
|
|
|
DWORD sz;
|
|
|
|
|
|
|
|
/* > is used if there is a component GUID and < if not. */
|
|
|
|
|
|
|
|
productid_85[0] = 0;
|
|
|
|
component_85[0] = 0;
|
|
|
|
CLSIDFromString( package->ProductCode, &clsid );
|
|
|
|
|
|
|
|
encode_base85_guid( &clsid, productid_85 );
|
|
|
|
if (component)
|
|
|
|
{
|
|
|
|
CLSIDFromString( component->ComponentId, &clsid );
|
|
|
|
encode_base85_guid( &clsid, component_85 );
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
|
|
|
|
debugstr_w(component_85));
|
|
|
|
|
|
|
|
sz = 20 + strlenW( feature ) + 20 + 3;
|
|
|
|
ret = msi_alloc_zero( sz * sizeof(WCHAR) );
|
|
|
|
if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
|
|
|
|
return ret;
|
|
|
|
}
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2010-03-01 12:01:30 +00:00
|
|
|
LPCWSTR compgroupid, component, feature, qualifier, text;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
|
2010-03-06 09:05:09 +00:00
|
|
|
HKEY hkey = NULL;
|
2010-03-01 12:01:30 +00:00
|
|
|
UINT rc;
|
2006-02-17 00:04:10 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-01 12:01:30 +00:00
|
|
|
MSIFEATURE *feat;
|
|
|
|
DWORD sz;
|
2006-08-01 23:12:11 +00:00
|
|
|
MSIRECORD *uirow;
|
2011-03-20 08:47:41 +00:00
|
|
|
int len;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
feature = MSI_RecordGetString(rec, 5);
|
2012-01-21 17:19:12 +00:00
|
|
|
feat = msi_get_loaded_feature(package, feature);
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!feat)
|
|
|
|
return ERROR_SUCCESS;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
feat->Action = msi_get_feature_action( package, feat );
|
|
|
|
if (feat->Action != INSTALLSTATE_LOCAL &&
|
|
|
|
feat->Action != INSTALLSTATE_SOURCE &&
|
|
|
|
feat->Action != INSTALLSTATE_ADVERTISED)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
|
2006-02-17 00:04:10 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
component = MSI_RecordGetString(rec, 3);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package, component);
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
compgroupid = MSI_RecordGetString(rec,1);
|
2006-08-01 23:12:11 +00:00
|
|
|
qualifier = MSI_RecordGetString(rec,2);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
advertise = msi_create_component_advertise_string( package, comp, feature );
|
2011-03-20 08:47:41 +00:00
|
|
|
text = MSI_RecordGetString( rec, 4 );
|
2006-02-17 00:04:10 +00:00
|
|
|
if (text)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
|
|
|
p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
|
|
|
|
strcpyW( p, advertise );
|
|
|
|
strcatW( p, text );
|
|
|
|
msi_free( advertise );
|
|
|
|
advertise = p;
|
|
|
|
}
|
|
|
|
existing = msi_reg_get_val_str( hkey, qualifier );
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
sz = strlenW( advertise ) + 1;
|
|
|
|
if (existing)
|
|
|
|
{
|
|
|
|
for (p = existing; *p; p += len)
|
|
|
|
{
|
|
|
|
len = strlenW( p ) + 1;
|
|
|
|
if (strcmpW( advertise, p )) sz += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
|
|
|
|
{
|
|
|
|
rc = ERROR_OUTOFMEMORY;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
q = output;
|
|
|
|
if (existing)
|
|
|
|
{
|
|
|
|
for (p = existing; *p; p += len)
|
|
|
|
{
|
|
|
|
len = strlenW( p ) + 1;
|
|
|
|
if (strcmpW( advertise, p ))
|
|
|
|
{
|
|
|
|
memcpy( q, p, len * sizeof(WCHAR) );
|
|
|
|
q += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcpyW( q, advertise );
|
|
|
|
q[strlenW( q ) + 1] = 0;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
|
|
|
msi_reg_set_val_multi_str( hkey, qualifier, output );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
end:
|
|
|
|
RegCloseKey(hkey);
|
2011-03-20 08:47:41 +00:00
|
|
|
msi_free( output );
|
|
|
|
msi_free( advertise );
|
|
|
|
msi_free( existing );
|
2006-08-01 23:12:11 +00:00
|
|
|
|
|
|
|
/* the UI chunk */
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, compgroupid );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, qualifier);
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2006-08-01 23:12:11 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
/* FIXME: call ui_progress? */
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* At present I am ignorning the advertised components part of this and only
|
|
|
|
* focusing on the qualified component sets
|
|
|
|
*/
|
|
|
|
static UINT ACTION_PublishComponents(MSIPACKAGE *package)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
|
|
|
|
MSIQUERY *view;
|
2006-02-17 00:04:10 +00:00
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szPublishComponents);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-02-17 00:04:10 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
|
|
|
static const WCHAR szInstallerComponents[] = {
|
|
|
|
'S','o','f','t','w','a','r','e','\\',
|
|
|
|
'M','i','c','r','o','s','o','f','t','\\',
|
|
|
|
'I','n','s','t','a','l','l','e','r','\\',
|
|
|
|
'C','o','m','p','o','n','e','n','t','s','\\',0};
|
|
|
|
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR compgroupid, component, feature, qualifier;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIFEATURE *feat;
|
|
|
|
MSIRECORD *uirow;
|
|
|
|
WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
|
|
|
|
LONG res;
|
|
|
|
|
|
|
|
feature = MSI_RecordGetString( rec, 5 );
|
2012-01-21 17:19:12 +00:00
|
|
|
feat = msi_get_loaded_feature( package, feature );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!feat)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
feat->Action = msi_get_feature_action( package, feat );
|
|
|
|
if (feat->Action != INSTALLSTATE_ABSENT)
|
2010-03-01 12:01:30 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( rec, 3 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
compgroupid = MSI_RecordGetString( rec, 1 );
|
|
|
|
qualifier = MSI_RecordGetString( rec, 2 );
|
|
|
|
|
|
|
|
squash_guid( compgroupid, squashed );
|
|
|
|
strcpyW( keypath, szInstallerComponents );
|
|
|
|
strcatW( keypath, squashed );
|
|
|
|
|
|
|
|
res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WARN("Unable to delete component key %d\n", res);
|
|
|
|
}
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, compgroupid );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, qualifier );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-01 12:01:30 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
|
2010-03-01 12:01:30 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szUnpublishComponents);
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] =
|
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
|
|
|
|
'`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2012-01-21 17:19:12 +00:00
|
|
|
MSICOMPONENT *component;
|
2006-10-22 20:23:59 +00:00
|
|
|
MSIRECORD *row;
|
|
|
|
MSIFILE *file;
|
2012-01-21 17:19:12 +00:00
|
|
|
SC_HANDLE hscm = NULL, service = NULL;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR comp, key;
|
|
|
|
LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
|
|
|
|
LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
|
|
|
|
DWORD serv_type, start_type, err_control;
|
2016-06-25 11:27:22 +00:00
|
|
|
BOOL is_vital;
|
2011-03-20 08:47:41 +00:00
|
|
|
SERVICE_DESCRIPTIONW sd = {NULL};
|
2012-12-09 19:43:59 +00:00
|
|
|
UINT ret = ERROR_SUCCESS;
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = MSI_RecordGetString( rec, 12 );
|
|
|
|
component = msi_get_loaded_component( package, comp );
|
|
|
|
if (!component)
|
|
|
|
{
|
|
|
|
WARN("service component not found\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
component->Action = msi_get_component_action( package, component );
|
|
|
|
if (component->Action != INSTALLSTATE_LOCAL)
|
|
|
|
{
|
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
|
|
|
|
goto done;
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
|
|
|
|
if (!hscm)
|
|
|
|
{
|
|
|
|
ERR("Failed to open the SC Manager!\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
start_type = MSI_RecordGetInteger(rec, 5);
|
|
|
|
if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
|
|
|
|
goto done;
|
|
|
|
|
2008-04-04 13:43:40 +00:00
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 2), &name);
|
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
|
2006-10-22 20:23:59 +00:00
|
|
|
serv_type = MSI_RecordGetInteger(rec, 4);
|
|
|
|
err_control = MSI_RecordGetInteger(rec, 6);
|
2011-03-20 08:47:41 +00:00
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
|
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
|
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
|
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
|
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 11), &args);
|
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2016-06-25 11:27:22 +00:00
|
|
|
/* Should the complete install fail if CreateService fails? */
|
|
|
|
is_vital = (err_control & msidbServiceInstallErrorControlVital);
|
|
|
|
|
|
|
|
/* Remove the msidbServiceInstallErrorControlVital-flag from err_control.
|
|
|
|
CreateService (under Windows) would fail if not. */
|
|
|
|
err_control &= ~msidbServiceInstallErrorControlVital;
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
/* fetch the service path */
|
|
|
|
row = MSI_QueryGetRecord(package->db, query, comp);
|
|
|
|
if (!row)
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
ERR("Query failed\n");
|
2006-10-22 20:23:59 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2014-04-23 14:48:52 +00:00
|
|
|
if (!(key = MSI_RecordGetString(row, 6)))
|
|
|
|
{
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
goto done;
|
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
file = msi_get_loaded_file(package, key);
|
2008-01-16 10:11:22 +00:00
|
|
|
msiobj_release(&row->hdr);
|
2006-10-22 20:23:59 +00:00
|
|
|
if (!file)
|
|
|
|
{
|
|
|
|
ERR("Failed to load the service file\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!args || !args[0]) image_path = file->TargetPath;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int len = strlenW(file->TargetPath) + strlenW(args) + 2;
|
|
|
|
if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
|
2012-12-09 19:43:59 +00:00
|
|
|
{
|
|
|
|
ret = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
|
|
|
|
strcpyW(image_path, file->TargetPath);
|
|
|
|
strcatW(image_path, szSpace);
|
|
|
|
strcatW(image_path, args);
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
|
2011-03-20 08:47:41 +00:00
|
|
|
start_type, err_control, image_path, load_order,
|
|
|
|
NULL, depends, serv_name, pass);
|
|
|
|
|
2006-10-22 20:23:59 +00:00
|
|
|
if (!service)
|
|
|
|
{
|
|
|
|
if (GetLastError() != ERROR_SERVICE_EXISTS)
|
2016-06-25 11:27:22 +00:00
|
|
|
{
|
|
|
|
WARN("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
|
|
|
|
if (is_vital)
|
|
|
|
ret = ERROR_INSTALL_FAILURE;
|
|
|
|
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
}
|
2011-03-20 08:47:41 +00:00
|
|
|
else if (sd.lpDescription)
|
|
|
|
{
|
|
|
|
if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
|
|
|
|
WARN("failed to set service description %u\n", GetLastError());
|
|
|
|
}
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (image_path != file->TargetPath) msi_free(image_path);
|
2006-10-22 20:23:59 +00:00
|
|
|
done:
|
2015-11-21 16:44:38 +00:00
|
|
|
if (service) CloseServiceHandle(service);
|
|
|
|
if (hscm) CloseServiceHandle(hscm);
|
2008-04-04 13:43:40 +00:00
|
|
|
msi_free(name);
|
|
|
|
msi_free(disp);
|
2011-03-20 08:47:41 +00:00
|
|
|
msi_free(sd.lpDescription);
|
|
|
|
msi_free(load_order);
|
|
|
|
msi_free(serv_name);
|
|
|
|
msi_free(pass);
|
|
|
|
msi_free(depends);
|
|
|
|
msi_free(args);
|
2006-10-22 20:23:59 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
return ret;
|
2006-10-22 20:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_InstallServices( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
|
|
|
|
MSIQUERY *view;
|
2006-10-22 20:23:59 +00:00
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szInstallServices);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2006-10-22 20:23:59 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
|
|
|
|
static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
LPCWSTR *vector, *temp_vector;
|
|
|
|
LPWSTR p, q;
|
|
|
|
DWORD sep_len;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR separator[] = {'[','~',']',0};
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
*numargs = 0;
|
2022-03-12 22:54:36 +00:00
|
|
|
sep_len = ARRAY_SIZE(separator) - 1;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!args)
|
|
|
|
return NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
vector = msi_alloc(sizeof(LPWSTR));
|
|
|
|
if (!vector)
|
|
|
|
return NULL;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
p = args;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
(*numargs)++;
|
|
|
|
vector[*numargs - 1] = p;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if ((q = strstrW(p, separator)))
|
|
|
|
{
|
|
|
|
*q = '\0';
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
|
|
|
|
if (!temp_vector)
|
|
|
|
{
|
|
|
|
msi_free(vector);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vector = temp_vector;
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
p = q + sep_len;
|
|
|
|
}
|
|
|
|
} while (q);
|
2006-02-17 00:04:10 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
return vector;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
|
2006-02-17 00:04:10 +00:00
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2008-01-16 10:11:22 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-05-29 08:55:43 +00:00
|
|
|
MSIRECORD *uirow;
|
2010-03-01 12:01:30 +00:00
|
|
|
SC_HANDLE scm = NULL, service = NULL;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR component, *vector = NULL;
|
2010-05-29 08:55:43 +00:00
|
|
|
LPWSTR name, args, display_name = NULL;
|
2012-01-21 17:19:12 +00:00
|
|
|
DWORD event, numargs, len, wait, dummy;
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT r = ERROR_FUNCTION_FAILED;
|
2012-01-21 17:19:12 +00:00
|
|
|
SERVICE_STATUS_PROCESS status;
|
|
|
|
ULONGLONG start_time;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
component = MSI_RecordGetString(rec, 6);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package, component);
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
event = MSI_RecordGetInteger( rec, 3 );
|
|
|
|
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
2015-03-09 20:28:19 +00:00
|
|
|
if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStart)) &&
|
|
|
|
!(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStart)))
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
TRACE("not starting %s\n", debugstr_w(name));
|
|
|
|
msi_free( name );
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
2010-03-06 09:05:09 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
deformat_string(package, MSI_RecordGetString(rec, 4), &args);
|
2012-01-21 17:19:12 +00:00
|
|
|
wait = MSI_RecordGetInteger(rec, 5);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
|
|
|
|
if (!scm)
|
|
|
|
{
|
|
|
|
ERR("Failed to open the service control manager\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
len = 0;
|
|
|
|
if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
|
|
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
{
|
|
|
|
if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
|
|
|
|
GetServiceDisplayNameW( scm, name, display_name, &len );
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (!service)
|
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
|
2008-01-16 10:11:22 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector = msi_service_args_to_vector(args, &numargs);
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
if (!StartServiceW(service, numargs, vector) &&
|
|
|
|
GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
|
2008-01-16 10:11:22 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
r = ERROR_SUCCESS;
|
|
|
|
if (wait)
|
|
|
|
{
|
|
|
|
/* wait for at most 30 seconds for the service to be up and running */
|
|
|
|
if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
|
|
|
|
(BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
|
|
|
|
{
|
|
|
|
TRACE("failed to query service status (%u)\n", GetLastError());
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
start_time = GetTickCount64();
|
|
|
|
while (status.dwCurrentState == SERVICE_START_PENDING)
|
|
|
|
{
|
|
|
|
if (GetTickCount64() - start_time > 30000) break;
|
|
|
|
Sleep(1000);
|
|
|
|
if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
|
|
|
|
(BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
|
|
|
|
{
|
|
|
|
TRACE("failed to query service status (%u)\n", GetLastError());
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (status.dwCurrentState != SERVICE_RUNNING)
|
|
|
|
{
|
|
|
|
WARN("service failed to start %u\n", status.dwCurrentState);
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
done:
|
2010-05-29 08:55:43 +00:00
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, display_name );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, name );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-05-29 08:55:43 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (service) CloseServiceHandle(service);
|
|
|
|
if (scm) CloseServiceHandle(scm);
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
msi_free(name);
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(args);
|
|
|
|
msi_free(vector);
|
2010-05-29 08:55:43 +00:00
|
|
|
msi_free(display_name);
|
2008-01-16 10:11:22 +00:00
|
|
|
return r;
|
2006-02-17 00:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_StartServices( MSIPACKAGE *package )
|
|
|
|
{
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szStartServices);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-04-04 13:43:40 +00:00
|
|
|
static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
|
|
|
|
{
|
|
|
|
DWORD i, needed, count;
|
|
|
|
ENUM_SERVICE_STATUSW *dependencies;
|
|
|
|
SERVICE_STATUS ss;
|
|
|
|
SC_HANDLE depserv;
|
2012-12-09 19:43:59 +00:00
|
|
|
BOOL stopped, ret = FALSE;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
|
|
|
if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
|
|
|
|
0, &needed, &count))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (GetLastError() != ERROR_MORE_DATA)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
dependencies = msi_alloc(needed);
|
|
|
|
if (!dependencies)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
|
|
|
|
needed, &needed, &count))
|
2012-12-09 19:43:59 +00:00
|
|
|
goto done;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
|
|
|
|
SERVICE_STOP | SERVICE_QUERY_STATUS);
|
|
|
|
if (!depserv)
|
2012-12-09 19:43:59 +00:00
|
|
|
goto done;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
stopped = ControlService(depserv, SERVICE_CONTROL_STOP, &ss);
|
|
|
|
CloseServiceHandle(depserv);
|
|
|
|
if (!stopped)
|
|
|
|
goto done;
|
2008-04-04 13:43:40 +00:00
|
|
|
}
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
ret = TRUE;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
done:
|
2008-04-04 13:43:40 +00:00
|
|
|
msi_free(dependencies);
|
2012-12-09 19:43:59 +00:00
|
|
|
return ret;
|
2008-04-04 13:43:40 +00:00
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static UINT stop_service( LPCWSTR name )
|
2008-04-04 13:43:40 +00:00
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
SC_HANDLE scm = NULL, service = NULL;
|
2008-04-04 13:43:40 +00:00
|
|
|
SERVICE_STATUS status;
|
|
|
|
SERVICE_STATUS_PROCESS ssp;
|
2010-02-06 21:28:28 +00:00
|
|
|
DWORD needed;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
|
|
|
scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (!scm)
|
|
|
|
{
|
|
|
|
WARN("Failed to open the SCM: %d\n", GetLastError());
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
service = OpenServiceW(scm, name,
|
|
|
|
SERVICE_STOP |
|
|
|
|
SERVICE_QUERY_STATUS |
|
|
|
|
SERVICE_ENUMERATE_DEPENDENTS);
|
|
|
|
if (!service)
|
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
|
2008-04-04 13:43:40 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
|
|
|
|
sizeof(SERVICE_STATUS_PROCESS), &needed))
|
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
|
2008-04-04 13:43:40 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ssp.dwCurrentState == SERVICE_STOPPED)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
stop_service_dependents(scm, service);
|
|
|
|
|
|
|
|
if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
|
|
|
|
WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
|
|
|
|
|
|
|
|
done:
|
2015-11-21 16:44:38 +00:00
|
|
|
if (service) CloseServiceHandle(service);
|
|
|
|
if (scm) CloseServiceHandle(scm);
|
2010-02-06 21:28:28 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
MSICOMPONENT *comp;
|
2010-05-29 08:55:43 +00:00
|
|
|
MSIRECORD *uirow;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR component;
|
2015-03-09 20:28:19 +00:00
|
|
|
WCHAR *name, *display_name = NULL;
|
2010-05-29 08:55:43 +00:00
|
|
|
DWORD event, len;
|
|
|
|
SC_HANDLE scm;
|
2010-02-06 21:28:28 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
component = MSI_RecordGetString( rec, 6 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2015-03-09 20:28:19 +00:00
|
|
|
event = MSI_RecordGetInteger( rec, 3 );
|
|
|
|
deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
2015-03-09 20:28:19 +00:00
|
|
|
if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStop)) &&
|
|
|
|
!(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStop)))
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
TRACE("not stopping %s\n", debugstr_w(name));
|
|
|
|
msi_free( name );
|
2010-02-06 21:28:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
2010-03-06 09:05:09 +00:00
|
|
|
}
|
2010-02-06 21:28:28 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
|
|
|
|
if (!scm)
|
|
|
|
{
|
|
|
|
ERR("Failed to open the service control manager\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
|
|
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
{
|
|
|
|
if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
|
|
|
|
GetServiceDisplayNameW( scm, name, display_name, &len );
|
|
|
|
}
|
|
|
|
CloseServiceHandle( scm );
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
stop_service( name );
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
done:
|
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, display_name );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, name );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-05-29 08:55:43 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
|
|
|
msi_free( name );
|
|
|
|
msi_free( display_name );
|
2008-04-04 13:43:40 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_StopServices( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szStopServices);
|
|
|
|
|
2008-04-04 13:43:40 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
|
|
|
LPWSTR name = NULL, display_name = NULL;
|
|
|
|
DWORD event, len;
|
2010-02-06 21:28:28 +00:00
|
|
|
SC_HANDLE scm = NULL, service = NULL;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
2010-02-06 21:28:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
event = MSI_RecordGetInteger( rec, 3 );
|
|
|
|
deformat_string( package, MSI_RecordGetString(rec, 2), &name );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
|
|
|
|
!(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2012-05-14 21:41:31 +00:00
|
|
|
TRACE("service %s not scheduled for removal\n", debugstr_w(name));
|
|
|
|
msi_free( name );
|
2010-03-06 09:05:09 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-02-06 21:28:28 +00:00
|
|
|
stop_service( name );
|
|
|
|
|
|
|
|
scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
|
|
|
|
if (!scm)
|
|
|
|
{
|
|
|
|
WARN("Failed to open the SCM: %d\n", GetLastError());
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
len = 0;
|
|
|
|
if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
|
|
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
{
|
|
|
|
if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
|
|
|
|
GetServiceDisplayNameW( scm, name, display_name, &len );
|
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
service = OpenServiceW( scm, name, DELETE );
|
|
|
|
if (!service)
|
|
|
|
{
|
|
|
|
WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DeleteService( service ))
|
|
|
|
WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
|
|
|
|
|
|
|
|
done:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, display_name );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, name );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (service) CloseServiceHandle( service );
|
|
|
|
if (scm) CloseServiceHandle( scm );
|
2010-02-06 21:28:28 +00:00
|
|
|
msi_free( name );
|
2010-03-06 09:05:09 +00:00
|
|
|
msi_free( display_name );
|
2010-02-06 21:28:28 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_DeleteServices( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
2010-02-06 21:28:28 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szDeleteServices);
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2008-01-16 10:11:22 +00:00
|
|
|
LPWSTR driver, driver_path, ptr;
|
|
|
|
WCHAR outpath[MAX_PATH];
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIFILE *driver_file = NULL, *setup_file = NULL;
|
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR desc, file_key, component;
|
2008-01-16 10:11:22 +00:00
|
|
|
DWORD len, usage;
|
|
|
|
UINT r = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
static const WCHAR driver_fmt[] = {
|
|
|
|
'D','r','i','v','e','r','=','%','s',0};
|
|
|
|
static const WCHAR setup_fmt[] = {
|
|
|
|
'S','e','t','u','p','=','%','s',0};
|
|
|
|
static const WCHAR usage_fmt[] = {
|
|
|
|
'F','i','l','e','U','s','a','g','e','=','1',0};
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
component = MSI_RecordGetString( rec, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
desc = MSI_RecordGetString(rec, 3);
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
file_key = MSI_RecordGetString( rec, 4 );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (file_key) driver_file = msi_get_loaded_file( package, file_key );
|
2011-03-20 08:47:41 +00:00
|
|
|
|
|
|
|
file_key = MSI_RecordGetString( rec, 5 );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (file_key) setup_file = msi_get_loaded_file( package, file_key );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!driver_file)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
ERR("ODBC Driver entry not found!\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
|
|
|
|
if (setup_file)
|
|
|
|
len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
|
2010-03-06 09:05:09 +00:00
|
|
|
len += lstrlenW(usage_fmt) + 2; /* \0\0 */
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
driver = msi_alloc(len * sizeof(WCHAR));
|
|
|
|
if (!driver)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
ptr = driver;
|
|
|
|
lstrcpyW(ptr, desc);
|
|
|
|
ptr += lstrlenW(ptr) + 1;
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
len = sprintfW(ptr, driver_fmt, driver_file->FileName);
|
|
|
|
ptr += len + 1;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
if (setup_file)
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
len = sprintfW(ptr, setup_fmt, setup_file->FileName);
|
|
|
|
ptr += len + 1;
|
2010-03-01 12:01:30 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
lstrcpyW(ptr, usage_fmt);
|
|
|
|
ptr += lstrlenW(ptr) + 1;
|
|
|
|
*ptr = '\0';
|
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
if (!driver_file->TargetPath)
|
|
|
|
{
|
|
|
|
const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
|
|
|
|
driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
driver_path = strdupW(driver_file->TargetPath);
|
|
|
|
ptr = strrchrW(driver_path, '\\');
|
|
|
|
if (ptr) *ptr = '\0';
|
|
|
|
|
|
|
|
if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
|
|
|
|
NULL, ODBC_INSTALL_COMPLETE, &usage))
|
|
|
|
{
|
|
|
|
ERR("Failed to install SQL driver!\n");
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 5 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, desc );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(driver);
|
|
|
|
msi_free(driver_path);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
2009-01-18 12:52:01 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2008-01-16 10:11:22 +00:00
|
|
|
LPWSTR translator, translator_path, ptr;
|
|
|
|
WCHAR outpath[MAX_PATH];
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIFILE *translator_file = NULL, *setup_file = NULL;
|
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR desc, file_key, component;
|
2008-01-16 10:11:22 +00:00
|
|
|
DWORD len, usage;
|
|
|
|
UINT r = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
static const WCHAR translator_fmt[] = {
|
|
|
|
'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
|
|
|
|
static const WCHAR setup_fmt[] = {
|
|
|
|
'S','e','t','u','p','=','%','s',0};
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
component = MSI_RecordGetString( rec, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
desc = MSI_RecordGetString(rec, 3);
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
file_key = MSI_RecordGetString( rec, 4 );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (file_key) translator_file = msi_get_loaded_file( package, file_key );
|
2011-03-20 08:47:41 +00:00
|
|
|
|
|
|
|
file_key = MSI_RecordGetString( rec, 5 );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (file_key) setup_file = msi_get_loaded_file( package, file_key );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
if (!translator_file)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
ERR("ODBC Translator entry not found!\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
|
2010-03-01 12:01:30 +00:00
|
|
|
if (setup_file)
|
|
|
|
len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
translator = msi_alloc(len * sizeof(WCHAR));
|
|
|
|
if (!translator)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
ptr = translator;
|
|
|
|
lstrcpyW(ptr, desc);
|
|
|
|
ptr += lstrlenW(ptr) + 1;
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
len = sprintfW(ptr, translator_fmt, translator_file->FileName);
|
|
|
|
ptr += len + 1;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
if (setup_file)
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
len = sprintfW(ptr, setup_fmt, setup_file->FileName);
|
|
|
|
ptr += len + 1;
|
2010-03-01 12:01:30 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
*ptr = '\0';
|
|
|
|
|
|
|
|
translator_path = strdupW(translator_file->TargetPath);
|
|
|
|
ptr = strrchrW(translator_path, '\\');
|
|
|
|
if (ptr) *ptr = '\0';
|
|
|
|
|
|
|
|
if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
|
|
|
|
NULL, ODBC_INSTALL_COMPLETE, &usage))
|
|
|
|
{
|
|
|
|
ERR("Failed to install SQL translator!\n");
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 5 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, desc );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
|
Sync aclui, advapi32, atl, authz, kernel32, msi, oledlg, powrprof, qmgr, riched20, samlib to Wine 1.2rc5
Update some psdk Headers to get some more synched winetests build
svn path=/trunk/; revision=47930
2010-07-03 12:42:55 +00:00
|
|
|
MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(translator);
|
|
|
|
msi_free(translator_path);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2011-03-20 08:47:41 +00:00
|
|
|
MSICOMPONENT *comp;
|
2008-01-16 10:11:22 +00:00
|
|
|
LPWSTR attrs;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR desc, driver, component;
|
2008-01-16 10:11:22 +00:00
|
|
|
WORD request = ODBC_ADD_SYS_DSN;
|
|
|
|
INT registration;
|
|
|
|
DWORD len;
|
|
|
|
UINT r = ERROR_SUCCESS;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
static const WCHAR attrs_fmt[] = {
|
|
|
|
'D','S','N','=','%','s',0 };
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
component = MSI_RecordGetString( rec, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
desc = MSI_RecordGetString(rec, 3);
|
|
|
|
driver = MSI_RecordGetString(rec, 4);
|
|
|
|
registration = MSI_RecordGetInteger(rec, 5);
|
|
|
|
|
|
|
|
if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
|
|
|
|
else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
|
2008-01-16 10:11:22 +00:00
|
|
|
attrs = msi_alloc(len * sizeof(WCHAR));
|
|
|
|
if (!attrs)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
len = sprintfW(attrs, attrs_fmt, desc);
|
|
|
|
attrs[len + 1] = 0;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
|
|
|
|
{
|
|
|
|
ERR("Failed to install SQL data source!\n");
|
|
|
|
r = ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 5 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, desc );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
|
|
|
|
MSI_RecordSetInteger( uirow, 3, request );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
msi_free(attrs);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_InstallODBC( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR driver_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','D','r','i','v','e','r',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR translator_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
static const WCHAR source_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szInstallODBC);
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2011-03-20 08:47:41 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2010-03-01 12:01:30 +00:00
|
|
|
DWORD usage;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR desc, component;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( rec, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-03-01 12:01:30 +00:00
|
|
|
|
|
|
|
desc = MSI_RecordGetString( rec, 3 );
|
|
|
|
if (!SQLRemoveDriverW( desc, FALSE, &usage ))
|
|
|
|
{
|
|
|
|
WARN("Failed to remove ODBC driver\n");
|
|
|
|
}
|
|
|
|
else if (!usage)
|
|
|
|
{
|
|
|
|
FIXME("Usage count reached 0\n");
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, desc );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2011-03-20 08:47:41 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2010-03-01 12:01:30 +00:00
|
|
|
DWORD usage;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR desc, component;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( rec, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-03-01 12:01:30 +00:00
|
|
|
|
|
|
|
desc = MSI_RecordGetString( rec, 3 );
|
|
|
|
if (!SQLRemoveTranslatorW( desc, &usage ))
|
|
|
|
{
|
|
|
|
WARN("Failed to remove ODBC translator\n");
|
|
|
|
}
|
|
|
|
else if (!usage)
|
|
|
|
{
|
|
|
|
FIXME("Usage count reached 0\n");
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 2 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, desc );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2011-03-20 08:47:41 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
2010-03-01 12:01:30 +00:00
|
|
|
LPWSTR attrs;
|
2011-03-20 08:47:41 +00:00
|
|
|
LPCWSTR desc, driver, component;
|
2010-03-01 12:01:30 +00:00
|
|
|
WORD request = ODBC_REMOVE_SYS_DSN;
|
|
|
|
INT registration;
|
|
|
|
DWORD len;
|
|
|
|
|
|
|
|
static const WCHAR attrs_fmt[] = {
|
|
|
|
'D','S','N','=','%','s',0 };
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
component = MSI_RecordGetString( rec, 2 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
desc = MSI_RecordGetString( rec, 3 );
|
|
|
|
driver = MSI_RecordGetString( rec, 4 );
|
|
|
|
registration = MSI_RecordGetInteger( rec, 5 );
|
|
|
|
|
|
|
|
if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
|
|
|
|
else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
|
2010-03-01 12:01:30 +00:00
|
|
|
attrs = msi_alloc( len * sizeof(WCHAR) );
|
|
|
|
if (!attrs)
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
FIXME("Use ODBCSourceAttribute table\n");
|
|
|
|
|
|
|
|
len = sprintfW( attrs, attrs_fmt, desc );
|
|
|
|
attrs[len + 1] = 0;
|
|
|
|
|
|
|
|
if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
|
|
|
|
{
|
|
|
|
WARN("Failed to remove ODBC data source\n");
|
|
|
|
}
|
|
|
|
msi_free( attrs );
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 3 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, desc );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
|
|
|
|
MSI_RecordSetInteger( uirow, 3, request );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR driver_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','D','r','i','v','e','r',0};
|
2010-03-01 12:01:30 +00:00
|
|
|
static const WCHAR translator_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
|
2010-03-01 12:01:30 +00:00
|
|
|
static const WCHAR source_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT rc;
|
2010-03-01 12:01:30 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveODBC);
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
2010-03-01 12:01:30 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
2010-03-01 12:01:30 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
2010-03-01 12:01:30 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
#define ENV_ACT_SETALWAYS 0x1
|
|
|
|
#define ENV_ACT_SETABSENT 0x2
|
|
|
|
#define ENV_ACT_REMOVE 0x4
|
|
|
|
#define ENV_ACT_REMOVEMATCH 0x8
|
|
|
|
|
|
|
|
#define ENV_MOD_MACHINE 0x20000000
|
|
|
|
#define ENV_MOD_APPEND 0x40000000
|
|
|
|
#define ENV_MOD_PREFIX 0x80000000
|
|
|
|
#define ENV_MOD_MASK 0xC0000000
|
|
|
|
|
|
|
|
#define check_flag_combo(x, y) ((x) & ~(y)) == (y)
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
LPCWSTR cptr = *name;
|
|
|
|
|
|
|
|
static const WCHAR prefix[] = {'[','~',']',0};
|
|
|
|
static const int prefix_len = 3;
|
|
|
|
|
|
|
|
*flags = 0;
|
|
|
|
while (*cptr)
|
|
|
|
{
|
|
|
|
if (*cptr == '=')
|
|
|
|
*flags |= ENV_ACT_SETALWAYS;
|
|
|
|
else if (*cptr == '+')
|
|
|
|
*flags |= ENV_ACT_SETABSENT;
|
|
|
|
else if (*cptr == '-')
|
|
|
|
*flags |= ENV_ACT_REMOVE;
|
|
|
|
else if (*cptr == '!')
|
|
|
|
*flags |= ENV_ACT_REMOVEMATCH;
|
|
|
|
else if (*cptr == '*')
|
|
|
|
*flags |= ENV_MOD_MACHINE;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
cptr++;
|
|
|
|
(*name)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*cptr)
|
|
|
|
{
|
|
|
|
ERR("Missing environment variable\n");
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2009-11-16 01:13:42 +00:00
|
|
|
if (*value)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2009-11-16 01:13:42 +00:00
|
|
|
LPCWSTR ptr = *value;
|
|
|
|
if (!strncmpW(ptr, prefix, prefix_len))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
if (ptr[prefix_len] == szSemiColon[0])
|
|
|
|
{
|
|
|
|
*flags |= ENV_MOD_APPEND;
|
|
|
|
*value += lstrlenW(prefix);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*value = NULL;
|
|
|
|
}
|
2009-11-16 01:13:42 +00:00
|
|
|
}
|
|
|
|
else if (lstrlenW(*value) >= prefix_len)
|
|
|
|
{
|
|
|
|
ptr += lstrlenW(ptr) - prefix_len;
|
2011-03-20 08:47:41 +00:00
|
|
|
if (!strcmpW( ptr, prefix ))
|
2009-11-16 01:13:42 +00:00
|
|
|
{
|
2010-02-06 21:28:28 +00:00
|
|
|
if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
|
|
|
|
{
|
|
|
|
*flags |= ENV_MOD_PREFIX;
|
|
|
|
/* the "[~]" will be removed by deformat_string */;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*value = NULL;
|
|
|
|
}
|
2009-11-16 01:13:42 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-17 21:16:57 +00:00
|
|
|
if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
|
2008-01-16 10:11:22 +00:00
|
|
|
check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
|
|
|
|
check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
|
|
|
|
check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
|
|
|
|
{
|
|
|
|
ERR("Invalid flags: %08x\n", *flags);
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2009-10-17 21:16:57 +00:00
|
|
|
if (!*flags)
|
|
|
|
*flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT open_env_key( DWORD flags, HKEY *key )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
static const WCHAR user_env[] =
|
|
|
|
{'E','n','v','i','r','o','n','m','e','n','t',0};
|
|
|
|
static const WCHAR machine_env[] =
|
|
|
|
{'S','y','s','t','e','m','\\',
|
|
|
|
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
|
|
'C','o','n','t','r','o','l','\\',
|
|
|
|
'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
|
|
|
|
'E','n','v','i','r','o','n','m','e','n','t',0};
|
2010-03-06 09:05:09 +00:00
|
|
|
const WCHAR *env;
|
|
|
|
HKEY root;
|
|
|
|
LONG res;
|
|
|
|
|
|
|
|
if (flags & ENV_MOD_MACHINE)
|
|
|
|
{
|
|
|
|
env = machine_env;
|
|
|
|
root = HKEY_LOCAL_MACHINE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
env = user_env;
|
|
|
|
root = HKEY_CURRENT_USER;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
LPCWSTR name, value, component;
|
2015-11-21 16:44:38 +00:00
|
|
|
WCHAR *data = NULL, *newval = NULL, *deformatted = NULL, *p, *q;
|
|
|
|
DWORD flags, type, size, len, len_value = 0;
|
2010-03-06 09:05:09 +00:00
|
|
|
UINT res;
|
|
|
|
HKEY env = NULL;
|
|
|
|
MSICOMPONENT *comp;
|
|
|
|
MSIRECORD *uirow;
|
2015-11-21 16:44:38 +00:00
|
|
|
int action = 0, found = 0;
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
component = MSI_RecordGetString(rec, 4);
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component(package, component);
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_LOCAL)
|
2010-03-06 09:05:09 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for installation %s\n", debugstr_w(component));
|
2010-03-06 09:05:09 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
name = MSI_RecordGetString(rec, 2);
|
|
|
|
value = MSI_RecordGetString(rec, 3);
|
|
|
|
|
2009-10-17 21:16:57 +00:00
|
|
|
TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
res = env_parse_flags(&name, &value, &flags);
|
2010-02-06 21:28:28 +00:00
|
|
|
if (res != ERROR_SUCCESS || !value)
|
2008-01-16 10:11:22 +00:00
|
|
|
goto done;
|
|
|
|
|
2009-11-16 01:13:42 +00:00
|
|
|
if (value && !deformat_string(package, value, &deformatted))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
res = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if ((value = deformatted))
|
|
|
|
{
|
|
|
|
if (flags & ENV_MOD_PREFIX)
|
|
|
|
{
|
|
|
|
p = strrchrW( value, ';' );
|
|
|
|
len_value = p - value;
|
|
|
|
}
|
|
|
|
else if (flags & ENV_MOD_APPEND)
|
|
|
|
{
|
|
|
|
value = strchrW( value, ';' ) + 1;
|
|
|
|
len_value = strlenW( value );
|
|
|
|
}
|
|
|
|
else len_value = strlenW( value );
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
res = open_env_key( flags, &env );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (flags & ENV_MOD_MACHINE)
|
|
|
|
action |= 0x20000000;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
size = 0;
|
2009-12-22 09:28:03 +00:00
|
|
|
type = REG_SZ;
|
2008-01-16 10:11:22 +00:00
|
|
|
res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
|
|
|
|
if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
|
|
|
|
(res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
|
|
|
|
goto done;
|
|
|
|
|
2009-12-22 09:28:03 +00:00
|
|
|
if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
action = 0x2;
|
|
|
|
|
2009-12-22 09:28:03 +00:00
|
|
|
/* Nothing to do. */
|
|
|
|
if (!value)
|
|
|
|
{
|
|
|
|
res = ERROR_SUCCESS;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
size = (lstrlenW(value) + 1) * sizeof(WCHAR);
|
|
|
|
newval = strdupW(value);
|
|
|
|
if (!newval)
|
|
|
|
{
|
|
|
|
res = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
action = 0x1;
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
/* Contrary to MSDN, +-variable to [~];path works */
|
|
|
|
if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
res = ERROR_SUCCESS;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (!(p = q = data = msi_alloc( size )))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2015-03-09 20:28:19 +00:00
|
|
|
msi_free(deformatted);
|
2008-01-16 10:11:22 +00:00
|
|
|
RegCloseKey(env);
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)data, &size );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
action = 0x4;
|
|
|
|
res = RegDeleteValueW(env, name);
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
|
2008-01-16 10:11:22 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
for (;;)
|
2009-12-22 09:28:03 +00:00
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
while (*q && *q != ';') q++;
|
|
|
|
len = q - p;
|
|
|
|
if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ) &&
|
|
|
|
(!p[len] || p[len] == ';'))
|
|
|
|
{
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!*q) break;
|
|
|
|
p = ++q;
|
2009-12-22 09:28:03 +00:00
|
|
|
}
|
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
TRACE("string already set\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = (len_value + 1 + strlenW( data ) + 1) * sizeof(WCHAR);
|
|
|
|
if (!(p = newval = msi_alloc( size )))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
res = ERROR_OUTOFMEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2009-12-22 09:28:03 +00:00
|
|
|
if (flags & ENV_MOD_PREFIX)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
memcpy( newval, value, len_value * sizeof(WCHAR) );
|
|
|
|
newval[len_value] = ';';
|
|
|
|
p = newval + len_value + 1;
|
2010-03-06 09:05:09 +00:00
|
|
|
action |= 0x80000000;
|
2009-12-22 09:28:03 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
strcpyW( p, data );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2009-12-22 09:28:03 +00:00
|
|
|
if (flags & ENV_MOD_APPEND)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
p += strlenW( data );
|
|
|
|
*p++ = ';';
|
|
|
|
memcpy( p, value, (len_value + 1) * sizeof(WCHAR) );
|
2010-03-06 09:05:09 +00:00
|
|
|
action |= 0x40000000;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
}
|
2010-02-06 21:28:28 +00:00
|
|
|
TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
|
2015-11-21 16:44:38 +00:00
|
|
|
res = RegSetValueExW( env, name, 0, type, (BYTE *)newval, size );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
|
|
|
done:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 3 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, name );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, newval );
|
|
|
|
MSI_RecordSetInteger( uirow, 3, action );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
if (env) RegCloseKey(env);
|
|
|
|
msi_free(deformatted);
|
|
|
|
msi_free(data);
|
|
|
|
msi_free(newval);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','E','n','v','i','r','o','n','m','e','n','t','`',0};
|
|
|
|
MSIQUERY *view;
|
2008-01-16 10:11:22 +00:00
|
|
|
UINT rc;
|
2012-01-21 17:19:12 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szWriteEnvironmentStrings);
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
2008-01-16 10:11:22 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
2010-03-06 09:05:09 +00:00
|
|
|
LPCWSTR name, value, component;
|
2015-11-21 16:44:38 +00:00
|
|
|
WCHAR *p, *q, *deformatted = NULL, *new_value = NULL;
|
|
|
|
DWORD flags, type, size, len, len_value = 0, len_new_value;
|
2010-03-06 09:05:09 +00:00
|
|
|
HKEY env;
|
2008-01-16 10:11:22 +00:00
|
|
|
MSICOMPONENT *comp;
|
2010-03-06 09:05:09 +00:00
|
|
|
MSIRECORD *uirow;
|
|
|
|
int action = 0;
|
|
|
|
LONG res;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
component = MSI_RecordGetString( rec, 4 );
|
2012-01-21 17:19:12 +00:00
|
|
|
comp = msi_get_loaded_component( package, component );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!comp)
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
comp->Action = msi_get_component_action( package, comp );
|
|
|
|
if (comp->Action != INSTALLSTATE_ABSENT)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("component not scheduled for removal %s\n", debugstr_w(component));
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-03-06 09:05:09 +00:00
|
|
|
name = MSI_RecordGetString( rec, 2 );
|
|
|
|
value = MSI_RecordGetString( rec, 3 );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
r = env_parse_flags( &name, &value, &flags );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (!(flags & ENV_ACT_REMOVE))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (value && !deformat_string( package, value, &deformatted ))
|
|
|
|
return ERROR_OUTOFMEMORY;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
if ((value = deformatted))
|
|
|
|
{
|
|
|
|
if (flags & ENV_MOD_PREFIX)
|
|
|
|
{
|
|
|
|
p = strchrW( value, ';' );
|
|
|
|
len_value = p - value;
|
|
|
|
}
|
|
|
|
else if (flags & ENV_MOD_APPEND)
|
|
|
|
{
|
|
|
|
value = strchrW( value, ';' ) + 1;
|
|
|
|
len_value = strlenW( value );
|
|
|
|
}
|
|
|
|
else len_value = strlenW( value );
|
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
r = open_env_key( flags, &env );
|
|
|
|
if (r != ERROR_SUCCESS)
|
2008-12-27 15:10:14 +00:00
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
r = ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
goto done;
|
2010-03-06 09:05:09 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (flags & ENV_MOD_MACHINE)
|
|
|
|
action |= 0x20000000;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
size = 0;
|
|
|
|
type = REG_SZ;
|
|
|
|
res = RegQueryValueExW( env, name, NULL, &type, NULL, &size );
|
|
|
|
if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (!(new_value = msi_alloc( size ))) goto done;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2015-11-21 16:44:38 +00:00
|
|
|
res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)new_value, &size );
|
2010-03-06 09:05:09 +00:00
|
|
|
if (res != ERROR_SUCCESS)
|
2015-11-21 16:44:38 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
len_new_value = size / sizeof(WCHAR) - 1;
|
|
|
|
p = q = new_value;
|
|
|
|
for (;;)
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2015-11-21 16:44:38 +00:00
|
|
|
while (*q && *q != ';') q++;
|
|
|
|
len = q - p;
|
|
|
|
if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ))
|
|
|
|
{
|
|
|
|
if (*q == ';') q++;
|
|
|
|
memmove( p, q, (len_new_value - (q - new_value) + 1) * sizeof(WCHAR) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!*q) break;
|
|
|
|
p = ++q;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!new_value[0] || !value)
|
|
|
|
{
|
|
|
|
TRACE("removing %s\n", debugstr_w(name));
|
|
|
|
res = RegDeleteValueW( env, name );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
WARN("failed to delete value %s (%d)\n", debugstr_w(name), res);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(new_value));
|
|
|
|
size = (strlenW( new_value ) + 1) * sizeof(WCHAR);
|
|
|
|
res = RegSetValueExW( env, name, 0, type, (BYTE *)new_value, size );
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
WARN("failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(new_value), res);
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2010-03-06 09:05:09 +00:00
|
|
|
uirow = MSI_CreateRecord( 3 );
|
|
|
|
MSI_RecordSetStringW( uirow, 1, name );
|
|
|
|
MSI_RecordSetStringW( uirow, 2, value );
|
|
|
|
MSI_RecordSetInteger( uirow, 3, action );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
if (env) RegCloseKey( env );
|
|
|
|
msi_free( deformatted );
|
2015-11-21 16:44:38 +00:00
|
|
|
msi_free( new_value );
|
2010-03-06 09:05:09 +00:00
|
|
|
return r;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','E','n','v','i','r','o','n','m','e','n','t','`',0};
|
2008-01-16 10:11:22 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2022-03-12 22:50:38 +00:00
|
|
|
if (package->script == SCRIPT_NONE)
|
|
|
|
return msi_schedule_action(package, SCRIPT_INSTALL, szRemoveEnvironmentStrings);
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
rc = MSI_DatabaseOpenViewW( package->db, query, &view );
|
2008-01-16 10:11:22 +00:00
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
|
2010-03-06 09:05:09 +00:00
|
|
|
rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2008-01-16 10:11:22 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT msi_validate_product_id( MSIPACKAGE *package )
|
2010-03-01 12:01:30 +00:00
|
|
|
{
|
|
|
|
LPWSTR key, template, id;
|
|
|
|
UINT r = ERROR_SUCCESS;
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
id = msi_dup_property( package->db, szProductID );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (id)
|
|
|
|
{
|
|
|
|
msi_free( id );
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2010-05-29 08:55:43 +00:00
|
|
|
template = msi_dup_property( package->db, szPIDTemplate );
|
|
|
|
key = msi_dup_property( package->db, szPIDKEY );
|
2010-03-01 12:01:30 +00:00
|
|
|
if (key && template)
|
|
|
|
{
|
|
|
|
FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
|
2019-03-17 22:14:46 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
WARN("Product key validation HACK, see CORE-14710\n");
|
|
|
|
#else
|
2012-12-09 19:43:59 +00:00
|
|
|
r = msi_set_property( package->db, szProductID, key, -1 );
|
2019-03-17 22:14:46 +00:00
|
|
|
#endif
|
2010-03-01 12:01:30 +00:00
|
|
|
}
|
|
|
|
msi_free( template );
|
|
|
|
msi_free( key );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
return msi_validate_product_id( package );
|
|
|
|
}
|
|
|
|
|
2010-02-06 21:28:28 +00:00
|
|
|
static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
TRACE("\n");
|
2012-05-14 21:41:31 +00:00
|
|
|
package->need_reboot_at_end = 1;
|
2010-02-06 21:28:28 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
|
|
|
|
{
|
2010-03-06 09:05:09 +00:00
|
|
|
static const WCHAR szAvailableFreeReg[] =
|
|
|
|
{'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
|
|
|
|
MSIRECORD *uirow;
|
2010-05-29 08:55:43 +00:00
|
|
|
int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
|
2010-03-06 09:05:09 +00:00
|
|
|
|
|
|
|
TRACE("%p %d kilobytes\n", package, space);
|
|
|
|
|
|
|
|
uirow = MSI_CreateRecord( 1 );
|
|
|
|
MSI_RecordSetInteger( uirow, 1, space );
|
2017-10-08 08:14:40 +00:00
|
|
|
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
|
2010-03-06 09:05:09 +00:00
|
|
|
msiobj_release( &uirow->hdr );
|
|
|
|
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_DisableRollback( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
TRACE("%p\n", package);
|
|
|
|
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
|
2010-03-01 12:01:30 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
FIXME("%p\n", package);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2010-05-29 08:55:43 +00:00
|
|
|
static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR driver_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','D','r','i','v','e','r',0};
|
2010-05-29 08:55:43 +00:00
|
|
|
static const WCHAR translator_query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
2012-01-21 17:19:12 +00:00
|
|
|
'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r, count;
|
2010-05-29 08:55:43 +00:00
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
r = MSI_IterateRecords( view, &count, NULL, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
2010-05-29 08:55:43 +00:00
|
|
|
if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
|
|
|
|
}
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
r = MSI_IterateRecords( view, &count, NULL, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
2010-05-29 08:55:43 +00:00
|
|
|
if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
2012-08-13 16:17:18 +00:00
|
|
|
static const WCHAR fmtW[] =
|
2016-11-22 12:25:27 +00:00
|
|
|
{'m','s','i','e','x','e','c',' ','/','q','n',' ','/','i',' ','%','s',' ',
|
|
|
|
'R','E','M','O','V','E','=','%','s',0};
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIPACKAGE *package = param;
|
2012-08-13 16:17:18 +00:00
|
|
|
const WCHAR *property = MSI_RecordGetString( rec, 7 );
|
2013-04-03 21:58:03 +00:00
|
|
|
int attrs = MSI_RecordGetInteger( rec, 5 );
|
2022-03-12 22:54:36 +00:00
|
|
|
UINT len = ARRAY_SIZE( fmtW );
|
2012-08-13 16:17:18 +00:00
|
|
|
WCHAR *product, *features, *cmd;
|
|
|
|
STARTUPINFOW si;
|
|
|
|
PROCESS_INFORMATION info;
|
|
|
|
BOOL ret;
|
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
if (attrs & msidbUpgradeAttributesOnlyDetect) return ERROR_SUCCESS;
|
2012-08-13 16:17:18 +00:00
|
|
|
if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
|
|
|
|
|
|
|
|
deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
|
|
|
|
|
|
|
|
len += strlenW( product );
|
|
|
|
if (features)
|
|
|
|
len += strlenW( features );
|
|
|
|
else
|
2022-03-12 22:54:36 +00:00
|
|
|
len += ARRAY_SIZE( szAll );
|
2011-03-20 08:47:41 +00:00
|
|
|
|
2012-08-13 16:17:18 +00:00
|
|
|
if (!(cmd = msi_alloc( len * sizeof(WCHAR) )))
|
2011-03-20 08:47:41 +00:00
|
|
|
{
|
2012-08-13 16:17:18 +00:00
|
|
|
msi_free( product );
|
|
|
|
msi_free( features );
|
|
|
|
return ERROR_OUTOFMEMORY;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
2012-08-13 16:17:18 +00:00
|
|
|
sprintfW( cmd, fmtW, product, features ? features : szAll );
|
|
|
|
msi_free( product );
|
|
|
|
msi_free( features );
|
|
|
|
|
|
|
|
memset( &si, 0, sizeof(STARTUPINFOW) );
|
|
|
|
ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
|
|
|
|
msi_free( cmd );
|
|
|
|
if (!ret) return GetLastError();
|
|
|
|
CloseHandle( info.hThread );
|
|
|
|
|
|
|
|
WaitForSingleObject( info.hProcess, INFINITE );
|
|
|
|
CloseHandle( info.hProcess );
|
2011-03-20 08:47:41 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
2012-08-13 16:17:18 +00:00
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0};
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT r;
|
2011-03-20 08:47:41 +00:00
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
int attributes = MSI_RecordGetInteger( rec, 5 );
|
|
|
|
|
|
|
|
if (attributes & msidbUpgradeAttributesMigrateFeatures)
|
|
|
|
{
|
|
|
|
const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
|
|
|
|
const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
|
|
|
|
const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
|
|
|
|
const WCHAR *language = MSI_RecordGetString( rec, 4 );
|
|
|
|
HKEY hkey;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
if (package->Context == MSIINSTALLCONTEXT_MACHINE)
|
|
|
|
{
|
|
|
|
r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
|
|
|
|
FIXME("migrate feature states from %s version min %s version max %s language %s\n",
|
|
|
|
debugstr_w(upgrade_code), debugstr_w(version_min),
|
|
|
|
debugstr_w(version_max), debugstr_w(language));
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'U','p','g','r','a','d','e',0};
|
2011-03-20 08:47:41 +00:00
|
|
|
MSIQUERY *view;
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT r;
|
2011-03-20 08:47:41 +00:00
|
|
|
|
|
|
|
if (msi_get_property_int( package->db, szInstalled, 0 ))
|
|
|
|
{
|
|
|
|
TRACE("product is installed, skipping action\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
if (msi_get_property_int( package->db, szPreselected, 0 ))
|
|
|
|
{
|
|
|
|
TRACE("Preselected property is set, not migrating feature states\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
|
|
|
|
msiobj_release( &view->hdr );
|
2012-01-21 17:19:12 +00:00
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
2011-03-20 08:47:41 +00:00
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static void bind_image( const char *filename, const char *path )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!BindImageEx( 0, filename, path, NULL, NULL ))
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
WARN("failed to bind image %u\n", GetLastError());
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
MSIFILE *file;
|
|
|
|
MSIPACKAGE *package = param;
|
|
|
|
const WCHAR *key = MSI_RecordGetString( rec, 1 );
|
|
|
|
const WCHAR *paths = MSI_RecordGetString( rec, 2 );
|
|
|
|
char *filenameA, *pathA;
|
|
|
|
WCHAR *pathW, **path_list;
|
2008-01-16 10:11:22 +00:00
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!(file = msi_get_loaded_file( package, key )))
|
|
|
|
{
|
|
|
|
WARN("file %s not found\n", debugstr_w(key));
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
|
|
|
|
path_list = msi_split_string( paths, ';' );
|
|
|
|
if (!path_list) bind_image( filenameA, NULL );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; path_list[i] && path_list[i][0]; i++)
|
|
|
|
{
|
|
|
|
deformat_string( package, path_list[i], &pathW );
|
|
|
|
if ((pathA = strdupWtoA( pathW )))
|
|
|
|
{
|
|
|
|
bind_image( filenameA, pathA );
|
|
|
|
msi_free( pathA );
|
|
|
|
}
|
|
|
|
msi_free( pathW );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
msi_free( path_list );
|
|
|
|
msi_free( filenameA );
|
2008-01-16 10:11:22 +00:00
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT ACTION_BindImage( MSIPACKAGE *package )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'B','i','n','d','I','m','a','g','e',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
r = MSI_DatabaseOpenViewW( package->db, query, &view );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
|
|
|
|
msiobj_release( &view->hdr );
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
|
2008-01-16 10:11:22 +00:00
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] = {
|
|
|
|
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
|
|
|
|
MSIQUERY *view;
|
|
|
|
DWORD count = 0;
|
|
|
|
UINT r;
|
|
|
|
|
|
|
|
r = MSI_OpenQuery( package->db, &view, query, table );
|
|
|
|
if (r == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
r = MSI_IterateRecords(view, &count, NULL, package);
|
|
|
|
msiobj_release(&view->hdr);
|
|
|
|
if (r != ERROR_SUCCESS)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
|
|
|
|
return ERROR_SUCCESS;
|
2008-01-16 10:11:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR table[] = {
|
2010-03-06 09:05:09 +00:00
|
|
|
'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
|
2008-01-16 10:11:22 +00:00
|
|
|
return msi_unimplemented_action_stub( package, "IsolateComponents", table );
|
|
|
|
}
|
|
|
|
|
2006-02-17 00:04:10 +00:00
|
|
|
static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
|
|
|
|
return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
|
|
|
|
}
|
|
|
|
|
2006-08-01 23:12:11 +00:00
|
|
|
static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
|
|
|
|
return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
|
|
|
|
return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
|
|
|
|
}
|
|
|
|
|
2008-01-16 10:11:22 +00:00
|
|
|
static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
|
|
|
|
{
|
|
|
|
static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
|
|
|
|
return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
|
|
|
|
}
|
|
|
|
|
2009-10-25 11:06:09 +00:00
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
const WCHAR *action;
|
2017-10-08 08:14:40 +00:00
|
|
|
const UINT description;
|
|
|
|
const UINT template;
|
2009-10-25 11:06:09 +00:00
|
|
|
UINT (*handler)(MSIPACKAGE *);
|
2012-01-21 17:19:12 +00:00
|
|
|
const WCHAR *action_rollback;
|
2009-10-25 11:06:09 +00:00
|
|
|
}
|
|
|
|
StandardActions[] =
|
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
{ szAllocateRegistrySpace, IDS_DESC_ALLOCATEREGISTRYSPACE, IDS_TEMP_ALLOCATEREGISTRYSPACE, ACTION_AllocateRegistrySpace, NULL },
|
|
|
|
{ szAppSearch, IDS_DESC_APPSEARCH, IDS_TEMP_APPSEARCH, ACTION_AppSearch, NULL },
|
|
|
|
{ szBindImage, IDS_DESC_BINDIMAGE, IDS_TEMP_BINDIMAGE, ACTION_BindImage, NULL },
|
|
|
|
{ szCCPSearch, IDS_DESC_CCPSEARCH, 0, ACTION_CCPSearch, NULL },
|
|
|
|
{ szCostFinalize, IDS_DESC_COSTFINALIZE, 0, ACTION_CostFinalize, NULL },
|
|
|
|
{ szCostInitialize, IDS_DESC_COSTINITIALIZE, 0, ACTION_CostInitialize, NULL },
|
|
|
|
{ szCreateFolders, IDS_DESC_CREATEFOLDERS, IDS_TEMP_CREATEFOLDERS, ACTION_CreateFolders, szRemoveFolders },
|
|
|
|
{ szCreateShortcuts, IDS_DESC_CREATESHORTCUTS, IDS_TEMP_CREATESHORTCUTS, ACTION_CreateShortcuts, szRemoveShortcuts },
|
|
|
|
{ szDeleteServices, IDS_DESC_DELETESERVICES, IDS_TEMP_DELETESERVICES, ACTION_DeleteServices, szInstallServices },
|
|
|
|
{ szDisableRollback, 0, 0, ACTION_DisableRollback, NULL },
|
|
|
|
{ szDuplicateFiles, IDS_DESC_DUPLICATEFILES, IDS_TEMP_DUPLICATEFILES, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
|
|
|
|
{ szExecuteAction, 0, 0, ACTION_ExecuteAction, NULL },
|
|
|
|
{ szFileCost, IDS_DESC_FILECOST, 0, ACTION_FileCost, NULL },
|
|
|
|
{ szFindRelatedProducts, IDS_DESC_FINDRELATEDPRODUCTS, IDS_TEMP_FINDRELATEDPRODUCTS, ACTION_FindRelatedProducts, NULL },
|
|
|
|
{ szForceReboot, 0, 0, ACTION_ForceReboot, NULL },
|
|
|
|
{ szInstallAdminPackage, IDS_DESC_INSTALLADMINPACKAGE, IDS_TEMP_INSTALLADMINPACKAGE, ACTION_InstallAdminPackage, NULL },
|
|
|
|
{ szInstallExecute, 0, 0, ACTION_InstallExecute, NULL },
|
|
|
|
{ szInstallExecuteAgain, 0, 0, ACTION_InstallExecute, NULL },
|
|
|
|
{ szInstallFiles, IDS_DESC_INSTALLFILES, IDS_TEMP_INSTALLFILES, ACTION_InstallFiles, szRemoveFiles },
|
|
|
|
{ szInstallFinalize, 0, 0, ACTION_InstallFinalize, NULL },
|
|
|
|
{ szInstallInitialize, 0, 0, ACTION_InstallInitialize, NULL },
|
|
|
|
{ szInstallODBC, IDS_DESC_INSTALLODBC, 0, ACTION_InstallODBC, szRemoveODBC },
|
|
|
|
{ szInstallServices, IDS_DESC_INSTALLSERVICES, IDS_TEMP_INSTALLSERVICES, ACTION_InstallServices, szDeleteServices },
|
|
|
|
{ szInstallSFPCatalogFile, IDS_DESC_INSTALLSFPCATALOGFILE, IDS_TEMP_INSTALLSFPCATALOGFILE, ACTION_InstallSFPCatalogFile, NULL },
|
|
|
|
{ szInstallValidate, IDS_DESC_INSTALLVALIDATE, 0, ACTION_InstallValidate, NULL },
|
|
|
|
{ szIsolateComponents, 0, 0, ACTION_IsolateComponents, NULL },
|
|
|
|
{ szLaunchConditions, IDS_DESC_LAUNCHCONDITIONS, 0, ACTION_LaunchConditions, NULL },
|
|
|
|
{ szMigrateFeatureStates, IDS_DESC_MIGRATEFEATURESTATES, IDS_TEMP_MIGRATEFEATURESTATES, ACTION_MigrateFeatureStates, NULL },
|
|
|
|
{ szMoveFiles, IDS_DESC_MOVEFILES, IDS_TEMP_MOVEFILES, ACTION_MoveFiles, NULL },
|
|
|
|
{ szMsiPublishAssemblies, IDS_DESC_MSIPUBLISHASSEMBLIES, IDS_TEMP_MSIPUBLISHASSEMBLIES, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
|
|
|
|
{ szMsiUnpublishAssemblies, IDS_DESC_MSIUNPUBLISHASSEMBLIES, IDS_TEMP_MSIUNPUBLISHASSEMBLIES, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
|
|
|
|
{ szPatchFiles, IDS_DESC_PATCHFILES, IDS_TEMP_PATCHFILES, ACTION_PatchFiles, NULL },
|
|
|
|
{ szProcessComponents, IDS_DESC_PROCESSCOMPONENTS, 0, ACTION_ProcessComponents, szProcessComponents },
|
|
|
|
{ szPublishComponents, IDS_DESC_PUBLISHCOMPONENTS, IDS_TEMP_PUBLISHCOMPONENTS, ACTION_PublishComponents, szUnpublishComponents },
|
|
|
|
{ szPublishFeatures, IDS_DESC_PUBLISHFEATURES, IDS_TEMP_PUBLISHFEATURES, ACTION_PublishFeatures, szUnpublishFeatures },
|
|
|
|
{ szPublishProduct, IDS_DESC_PUBLISHPRODUCT, 0, ACTION_PublishProduct, szUnpublishProduct },
|
|
|
|
{ szRegisterClassInfo, IDS_DESC_REGISTERCLASSINFO, IDS_TEMP_REGISTERCLASSINFO, ACTION_RegisterClassInfo, szUnregisterClassInfo },
|
|
|
|
{ szRegisterComPlus, IDS_DESC_REGISTERCOMPLUS, IDS_TEMP_REGISTERCOMPLUS, ACTION_RegisterComPlus, szUnregisterComPlus },
|
|
|
|
{ szRegisterExtensionInfo, IDS_DESC_REGISTEREXTENSIONINFO, 0, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
|
|
|
|
{ szRegisterFonts, IDS_DESC_REGISTERFONTS, IDS_TEMP_REGISTERFONTS, ACTION_RegisterFonts, szUnregisterFonts },
|
|
|
|
{ szRegisterMIMEInfo, IDS_DESC_REGISTERMIMEINFO, IDS_TEMP_REGISTERMIMEINFO, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
|
|
|
|
{ szRegisterProduct, IDS_DESC_REGISTERPRODUCT, 0, ACTION_RegisterProduct, NULL },
|
|
|
|
{ szRegisterProgIdInfo, IDS_DESC_REGISTERPROGIDINFO, IDS_TEMP_REGISTERPROGIDINFO, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
|
|
|
|
{ szRegisterTypeLibraries, IDS_DESC_REGISTERTYPELIBRARIES, IDS_TEMP_REGISTERTYPELIBRARIES, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
|
|
|
|
{ szRegisterUser, IDS_DESC_REGISTERUSER, 0, ACTION_RegisterUser, NULL },
|
|
|
|
{ szRemoveDuplicateFiles, IDS_DESC_REMOVEDUPLICATEFILES, IDS_TEMP_REMOVEDUPLICATEFILES, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
|
|
|
|
{ szRemoveEnvironmentStrings, IDS_DESC_REMOVEENVIRONMENTSTRINGS, IDS_TEMP_REMOVEENVIRONMENTSTRINGS, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
|
|
|
|
{ szRemoveExistingProducts, IDS_DESC_REMOVEEXISTINGPRODUCTS, IDS_TEMP_REMOVEEXISTINGPRODUCTS, ACTION_RemoveExistingProducts, NULL },
|
|
|
|
{ szRemoveFiles, IDS_DESC_REMOVEFILES, IDS_TEMP_REMOVEFILES, ACTION_RemoveFiles, szInstallFiles },
|
|
|
|
{ szRemoveFolders, IDS_DESC_REMOVEFOLDERS, IDS_TEMP_REMOVEFOLDERS, ACTION_RemoveFolders, szCreateFolders },
|
|
|
|
{ szRemoveIniValues, IDS_DESC_REMOVEINIVALUES, IDS_TEMP_REMOVEINIVALUES, ACTION_RemoveIniValues, szWriteIniValues },
|
|
|
|
{ szRemoveODBC, IDS_DESC_REMOVEODBC, 0, ACTION_RemoveODBC, szInstallODBC },
|
|
|
|
{ szRemoveRegistryValues, IDS_DESC_REMOVEREGISTRYVALUES, IDS_TEMP_REMOVEREGISTRYVALUES, ACTION_RemoveRegistryValues, szWriteRegistryValues },
|
|
|
|
{ szRemoveShortcuts, IDS_DESC_REMOVESHORTCUTS, IDS_TEMP_REMOVESHORTCUTS, ACTION_RemoveShortcuts, szCreateShortcuts },
|
|
|
|
{ szResolveSource, 0, 0, ACTION_ResolveSource, NULL },
|
|
|
|
{ szRMCCPSearch, IDS_DESC_RMCCPSEARCH, 0, ACTION_RMCCPSearch, NULL },
|
|
|
|
{ szScheduleReboot, 0, 0, ACTION_ScheduleReboot, NULL },
|
|
|
|
{ szSelfRegModules, IDS_DESC_SELFREGMODULES, IDS_TEMP_SELFREGMODULES, ACTION_SelfRegModules, szSelfUnregModules },
|
|
|
|
{ szSelfUnregModules, IDS_DESC_SELFUNREGMODULES, IDS_TEMP_SELFUNREGMODULES, ACTION_SelfUnregModules, szSelfRegModules },
|
|
|
|
{ szSetODBCFolders, IDS_DESC_SETODBCFOLDERS, 0, ACTION_SetODBCFolders, NULL },
|
|
|
|
{ szStartServices, IDS_DESC_STARTSERVICES, IDS_TEMP_STARTSERVICES, ACTION_StartServices, szStopServices },
|
|
|
|
{ szStopServices, IDS_DESC_STOPSERVICES, IDS_TEMP_STOPSERVICES, ACTION_StopServices, szStartServices },
|
|
|
|
{ szUnpublishComponents, IDS_DESC_UNPUBLISHCOMPONENTS, IDS_TEMP_UNPUBLISHCOMPONENTS, ACTION_UnpublishComponents, szPublishComponents },
|
|
|
|
{ szUnpublishFeatures, IDS_DESC_UNPUBLISHFEATURES, IDS_TEMP_UNPUBLISHFEATURES, ACTION_UnpublishFeatures, szPublishFeatures },
|
|
|
|
{ szUnpublishProduct, IDS_DESC_UNPUBLISHPRODUCT, 0, ACTION_UnpublishProduct, NULL }, /* for rollback only */
|
|
|
|
{ szUnregisterClassInfo, IDS_DESC_UNREGISTERCLASSINFO, IDS_TEMP_UNREGISTERCLASSINFO, ACTION_UnregisterClassInfo, szRegisterClassInfo },
|
|
|
|
{ szUnregisterComPlus, IDS_DESC_UNREGISTERCOMPLUS, IDS_TEMP_UNREGISTERCOMPLUS, ACTION_UnregisterComPlus, szRegisterComPlus },
|
|
|
|
{ szUnregisterExtensionInfo, IDS_DESC_UNREGISTEREXTENSIONINFO, IDS_TEMP_UNREGISTEREXTENSIONINFO, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
|
|
|
|
{ szUnregisterFonts, IDS_DESC_UNREGISTERFONTS, IDS_TEMP_UNREGISTERFONTS, ACTION_UnregisterFonts, szRegisterFonts },
|
|
|
|
{ szUnregisterMIMEInfo, IDS_DESC_UNREGISTERMIMEINFO, IDS_TEMP_UNREGISTERMIMEINFO, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
|
|
|
|
{ szUnregisterProgIdInfo, IDS_DESC_UNREGISTERPROGIDINFO, IDS_TEMP_UNREGISTERPROGIDINFO, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
|
|
|
|
{ szUnregisterTypeLibraries, IDS_DESC_UNREGISTERTYPELIBRARIES, IDS_TEMP_UNREGISTERTYPELIBRARIES, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
|
|
|
|
{ szValidateProductID, 0, 0, ACTION_ValidateProductID, NULL },
|
|
|
|
{ szWriteEnvironmentStrings, IDS_DESC_WRITEENVIRONMENTSTRINGS, IDS_TEMP_WRITEENVIRONMENTSTRINGS, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
|
|
|
|
{ szWriteIniValues, IDS_DESC_WRITEINIVALUES, IDS_TEMP_WRITEINIVALUES, ACTION_WriteIniValues, szRemoveIniValues },
|
|
|
|
{ szWriteRegistryValues, IDS_DESC_WRITEREGISTRYVALUES, IDS_TEMP_WRITEREGISTRYVALUES, ACTION_WriteRegistryValues, szRemoveRegistryValues },
|
2018-01-20 11:29:30 +00:00
|
|
|
{ szINSTALL, 0, 0, ACTION_INSTALL, NULL },
|
2017-10-08 08:14:40 +00:00
|
|
|
{ 0 }
|
2006-02-17 00:04:10 +00:00
|
|
|
};
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
static UINT ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action)
|
2008-04-04 13:43:40 +00:00
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
UINT rc = ERROR_FUNCTION_NOT_CALLED;
|
2022-03-12 14:12:12 +00:00
|
|
|
void *cookie;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
UINT i;
|
2008-04-04 13:43:40 +00:00
|
|
|
|
2022-03-12 14:12:12 +00:00
|
|
|
if (is_wow64 && package->platform == PLATFORM_X64)
|
|
|
|
Wow64DisableWow64FsRedirection(&cookie);
|
|
|
|
|
2008-04-04 13:43:40 +00:00
|
|
|
i = 0;
|
|
|
|
while (StandardActions[i].action != NULL)
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!strcmpW( StandardActions[i].action, action ))
|
2008-04-04 13:43:40 +00:00
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
WCHAR description[100] = {0}, template[100] = {0};
|
|
|
|
|
|
|
|
if (StandardActions[i].description != 0)
|
|
|
|
LoadStringW(msi_hInstance, StandardActions[i].description, (LPWSTR)&description, 100);
|
|
|
|
if (StandardActions[i].template != 0)
|
|
|
|
LoadStringW(msi_hInstance, StandardActions[i].template, (LPWSTR)&template, 100);
|
|
|
|
|
|
|
|
ui_actionstart(package, action, description, template);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (StandardActions[i].handler)
|
2008-04-04 13:43:40 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
ui_actioninfo( package, action, TRUE, 0 );
|
2017-10-08 08:14:40 +00:00
|
|
|
rc = StandardActions[i].handler( package );
|
|
|
|
ui_actioninfo( package, action, FALSE, !rc );
|
2012-01-21 17:19:12 +00:00
|
|
|
|
|
|
|
if (StandardActions[i].action_rollback && !package->need_rollback)
|
|
|
|
{
|
|
|
|
TRACE("scheduling rollback action\n");
|
|
|
|
msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
|
|
|
|
}
|
2008-04-04 13:43:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
FIXME("unhandled standard action %s\n", debugstr_w(action));
|
2017-10-08 08:14:40 +00:00
|
|
|
rc = ERROR_SUCCESS;
|
2008-04-04 13:43:40 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2022-03-12 14:12:12 +00:00
|
|
|
|
|
|
|
if (is_wow64 && package->platform == PLATFORM_X64)
|
|
|
|
Wow64RevertWow64FsRedirection(cookie);
|
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
return rc;
|
2008-04-04 13:43:40 +00:00
|
|
|
}
|
2009-10-25 11:06:09 +00:00
|
|
|
|
2022-03-12 15:34:06 +00:00
|
|
|
UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
|
2009-10-25 11:06:09 +00:00
|
|
|
{
|
2017-10-08 08:14:40 +00:00
|
|
|
UINT rc;
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
TRACE("Performing action (%s)\n", debugstr_w(action));
|
|
|
|
|
2012-08-13 16:17:18 +00:00
|
|
|
package->action_progress_increment = 0;
|
2017-10-08 08:14:40 +00:00
|
|
|
rc = ACTION_HandleStandardAction(package, action);
|
2009-10-25 11:06:09 +00:00
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
if (rc == ERROR_FUNCTION_NOT_CALLED)
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_HandleCustomAction(package, action);
|
2009-10-25 11:06:09 +00:00
|
|
|
|
2017-10-08 08:14:40 +00:00
|
|
|
if (rc == ERROR_FUNCTION_NOT_CALLED)
|
2009-10-25 11:06:09 +00:00
|
|
|
WARN("unhandled msi action %s\n", debugstr_w(action));
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
|
|
|
|
{
|
|
|
|
UINT rc = ERROR_SUCCESS;
|
|
|
|
MSIRECORD *row;
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR query[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
|
|
|
|
'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
|
|
|
|
'`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR ui_query[] =
|
2009-10-25 11:06:09 +00:00
|
|
|
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
|
|
|
'`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
|
|
|
|
'`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
|
|
|
|
' ', '=',' ','%','i',0};
|
|
|
|
|
|
|
|
if (needs_ui_sequence(package))
|
2012-01-21 17:19:12 +00:00
|
|
|
row = MSI_QueryGetRecord(package->db, ui_query, seq);
|
2009-10-25 11:06:09 +00:00
|
|
|
else
|
2012-01-21 17:19:12 +00:00
|
|
|
row = MSI_QueryGetRecord(package->db, query, seq);
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
if (row)
|
|
|
|
{
|
|
|
|
LPCWSTR action, cond;
|
|
|
|
|
|
|
|
TRACE("Running the actions\n");
|
|
|
|
|
|
|
|
/* check conditions */
|
|
|
|
cond = MSI_RecordGetString(row, 2);
|
|
|
|
|
|
|
|
/* this is a hack to skip errors in the condition code */
|
|
|
|
if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
|
|
|
|
{
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
action = MSI_RecordGetString(row, 1);
|
|
|
|
if (!action)
|
|
|
|
{
|
|
|
|
ERR("failed to fetch action\n");
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
return ERROR_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_PerformAction(package, action);
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
msiobj_release(&row->hdr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
DWORD WINAPI dummy_thread_proc(void *arg)
|
|
|
|
{
|
|
|
|
struct dummy_thread *info = arg;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
|
|
|
|
if (FAILED(hr)) ERR("CoInitializeEx failed %08x\n", hr);
|
|
|
|
|
|
|
|
SetEvent(info->started);
|
|
|
|
WaitForSingleObject(info->stopped, INFINITE);
|
|
|
|
|
|
|
|
CoUninitialize();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void start_dummy_thread(struct dummy_thread *info)
|
|
|
|
{
|
|
|
|
if (!(info->started = CreateEventA(NULL, TRUE, FALSE, NULL))) return;
|
|
|
|
if (!(info->stopped = CreateEventA(NULL, TRUE, FALSE, NULL))) return;
|
|
|
|
if (!(info->thread = CreateThread(NULL, 0, dummy_thread_proc, info, 0, NULL))) return;
|
|
|
|
|
|
|
|
WaitForSingleObject(info->started, INFINITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stop_dummy_thread(struct dummy_thread *info)
|
|
|
|
{
|
|
|
|
if (info->thread)
|
|
|
|
{
|
|
|
|
SetEvent(info->stopped);
|
|
|
|
WaitForSingleObject(info->thread, INFINITE);
|
|
|
|
CloseHandle(info->thread);
|
|
|
|
}
|
|
|
|
if (info->started) CloseHandle(info->started);
|
|
|
|
if (info->stopped) CloseHandle(info->stopped);
|
|
|
|
}
|
|
|
|
|
2009-10-25 11:06:09 +00:00
|
|
|
/****************************************************
|
|
|
|
* TOP level entry points
|
|
|
|
*****************************************************/
|
|
|
|
|
|
|
|
UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
|
|
|
|
LPCWSTR szCommandLine )
|
|
|
|
{
|
2012-01-21 17:19:12 +00:00
|
|
|
static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
|
2009-10-25 11:06:09 +00:00
|
|
|
static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
|
2018-01-20 11:29:30 +00:00
|
|
|
WCHAR *reinstall = NULL, *productcode, *action;
|
2018-03-04 23:30:58 +00:00
|
|
|
struct dummy_thread thread_info = {NULL, NULL, NULL};
|
2012-01-21 17:19:12 +00:00
|
|
|
UINT rc;
|
2018-01-20 11:29:30 +00:00
|
|
|
DWORD len = 0;
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
if (szPackagePath)
|
|
|
|
{
|
|
|
|
LPWSTR p, dir;
|
|
|
|
LPCWSTR file;
|
|
|
|
|
|
|
|
dir = strdupW(szPackagePath);
|
|
|
|
p = strrchrW(dir, '\\');
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
*(++p) = 0;
|
|
|
|
file = szPackagePath + (p - dir);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msi_free(dir);
|
|
|
|
dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
|
|
|
|
GetCurrentDirectoryW(MAX_PATH, dir);
|
|
|
|
lstrcatW(dir, szBackSlash);
|
|
|
|
file = szPackagePath;
|
|
|
|
}
|
|
|
|
|
|
|
|
msi_free( package->PackagePath );
|
|
|
|
package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
|
|
|
|
if (!package->PackagePath)
|
|
|
|
{
|
|
|
|
msi_free(dir);
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
lstrcpyW(package->PackagePath, dir);
|
|
|
|
lstrcatW(package->PackagePath, file);
|
|
|
|
msi_free(dir);
|
|
|
|
|
|
|
|
msi_set_sourcedir_props(package, FALSE);
|
|
|
|
}
|
|
|
|
|
2011-03-20 08:47:41 +00:00
|
|
|
rc = msi_parse_command_line( package, szCommandLine, FALSE );
|
|
|
|
if (rc != ERROR_SUCCESS)
|
|
|
|
return rc;
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
msi_apply_transforms( package );
|
|
|
|
msi_apply_patches( package );
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
if (msi_get_property( package->db, szAction, NULL, &len ))
|
|
|
|
msi_set_property( package->db, szAction, szINSTALL, -1 );
|
|
|
|
action = msi_dup_property( package->db, szAction );
|
|
|
|
CharUpperW(action);
|
2009-10-25 11:06:09 +00:00
|
|
|
|
2013-04-03 21:58:03 +00:00
|
|
|
msi_set_original_database_property( package->db, szPackagePath );
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
msi_parse_command_line( package, szCommandLine, FALSE );
|
2010-10-22 13:18:11 +00:00
|
|
|
msi_adjust_privilege_properties( package );
|
2009-10-25 11:06:09 +00:00
|
|
|
msi_set_context( package );
|
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
start_dummy_thread(&thread_info);
|
|
|
|
|
2014-09-23 18:32:48 +00:00
|
|
|
productcode = msi_dup_property( package->db, szProductCode );
|
|
|
|
if (strcmpiW( productcode, package->ProductCode ))
|
|
|
|
{
|
|
|
|
TRACE( "product code changed %s -> %s\n", debugstr_w(package->ProductCode), debugstr_w(productcode) );
|
|
|
|
msi_free( package->ProductCode );
|
|
|
|
package->ProductCode = productcode;
|
|
|
|
}
|
|
|
|
else msi_free( productcode );
|
|
|
|
|
2012-01-21 17:19:12 +00:00
|
|
|
if (msi_get_property_int( package->db, szDisableRollback, 0 ))
|
|
|
|
{
|
|
|
|
TRACE("disabling rollback\n");
|
2012-12-09 19:43:59 +00:00
|
|
|
msi_set_property( package->db, szRollbackDisabled, szOne, -1 );
|
2012-01-21 17:19:12 +00:00
|
|
|
}
|
|
|
|
|
2022-03-12 15:34:06 +00:00
|
|
|
rc = ACTION_PerformAction(package, action);
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
/* process the ending type action */
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
ACTION_PerformActionSequence(package, -1);
|
|
|
|
else if (rc == ERROR_INSTALL_USEREXIT)
|
|
|
|
ACTION_PerformActionSequence(package, -2);
|
|
|
|
else if (rc == ERROR_INSTALL_SUSPEND)
|
|
|
|
ACTION_PerformActionSequence(package, -4);
|
|
|
|
else /* failed */
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
2009-10-25 11:06:09 +00:00
|
|
|
ACTION_PerformActionSequence(package, -3);
|
2012-01-21 17:19:12 +00:00
|
|
|
if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
|
|
|
|
{
|
|
|
|
package->need_rollback = TRUE;
|
|
|
|
}
|
|
|
|
}
|
2009-10-25 11:06:09 +00:00
|
|
|
|
|
|
|
/* finish up running custom actions */
|
|
|
|
ACTION_FinishCustomActions(package);
|
|
|
|
|
2018-03-04 23:30:58 +00:00
|
|
|
stop_dummy_thread(&thread_info);
|
|
|
|
|
2018-01-20 11:29:30 +00:00
|
|
|
if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall )))
|
2012-01-21 17:19:12 +00:00
|
|
|
{
|
|
|
|
WARN("installation failed, running rollback script\n");
|
|
|
|
execute_script( package, SCRIPT_ROLLBACK );
|
|
|
|
}
|
|
|
|
msi_free( reinstall );
|
2018-01-20 11:29:30 +00:00
|
|
|
msi_free( action );
|
2012-01-21 17:19:12 +00:00
|
|
|
|
2012-05-14 21:41:31 +00:00
|
|
|
if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
|
2009-10-25 11:06:09 +00:00
|
|
|
return ERROR_SUCCESS_REBOOT_REQUIRED;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|