AMSICA => MSICALib
This commit is contained in:
parent
1328e5c474
commit
a00c2f3c91
88
FileOp.cpp
Normal file
88
FileOp.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace MSICA {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpFileDelete
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpFileDelete::COpFileDelete(LPCWSTR pszFileName, int iTicks) :
|
||||||
|
COpTypeSingleString(pszFileName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpFileDelete::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
DWORD dwError;
|
||||||
|
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
ATL::CAtlStringW sBackupName;
|
||||||
|
UINT uiCount = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Rename the file to make a backup.
|
||||||
|
sBackupName.Format(L"%ls (orig %u)", (LPCWSTR)m_sValue, ++uiCount);
|
||||||
|
dwError = ::MoveFileW(m_sValue, sBackupName) ? ERROR_SUCCESS : ::GetLastError();
|
||||||
|
} while (dwError == ERROR_ALREADY_EXISTS);
|
||||||
|
if (dwError == ERROR_SUCCESS) {
|
||||||
|
// Order rollback action to restore from backup copy.
|
||||||
|
pSession->m_olRollback.AddHead(new COpFileMove(sBackupName, m_sValue));
|
||||||
|
|
||||||
|
// Order commit action to delete backup copy.
|
||||||
|
pSession->m_olCommit.AddTail(new COpFileDelete(sBackupName));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Delete the file.
|
||||||
|
dwError = ::DeleteFileW(m_sValue) ? ERROR_SUCCESS : ::GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwError == ERROR_SUCCESS || dwError == ERROR_FILE_NOT_FOUND)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(3);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_FILE_DELETE_FAILED);
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 2, m_sValue );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 3, dwError );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(dwError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpFileMove
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpFileMove::COpFileMove(LPCWSTR pszFileSrc, LPCWSTR pszFileDst, int iTicks) :
|
||||||
|
COpTypeSrcDstString(pszFileSrc, pszFileDst, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpFileMove::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
DWORD dwError;
|
||||||
|
|
||||||
|
// Move the file.
|
||||||
|
dwError = ::MoveFileW(m_sValue1, m_sValue2) ? ERROR_SUCCESS : ::GetLastError();
|
||||||
|
if (dwError == ERROR_SUCCESS) {
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Order rollback action to move it back.
|
||||||
|
pSession->m_olRollback.AddHead(new COpFileMove(m_sValue2, m_sValue1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
} else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(4);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_FILE_MOVE_FAILED);
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 2, m_sValue1 );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue2 );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 4, dwError );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(dwError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace MSICA
|
184
MSICALib.cpp
Normal file
184
MSICALib.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#pragma comment(lib, "msi.lib")
|
||||||
|
|
||||||
|
|
||||||
|
namespace MSICA {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COperation
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COperation::COperation(int iTicks) :
|
||||||
|
m_iTicks(iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpTypeSingleString
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpTypeSingleString::COpTypeSingleString(LPCWSTR pszValue, int iTicks) :
|
||||||
|
m_sValue(pszValue),
|
||||||
|
COperation(iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpTypeSrcDstString
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpTypeSrcDstString::COpTypeSrcDstString(LPCWSTR pszValue1, LPCWSTR pszValue2, int iTicks) :
|
||||||
|
m_sValue1(pszValue1),
|
||||||
|
m_sValue2(pszValue2),
|
||||||
|
COperation(iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpTypeBoolean
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpTypeBoolean::COpTypeBoolean(BOOL bValue, int iTicks) :
|
||||||
|
m_bValue(bValue),
|
||||||
|
COperation(iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRollbackEnable
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRollbackEnable::COpRollbackEnable(BOOL bEnable, int iTicks) :
|
||||||
|
COpTypeBoolean(bEnable, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRollbackEnable::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
pSession->m_bRollbackEnabled = m_bValue;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpList
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpList::COpList(int iTicks) :
|
||||||
|
COperation(iTicks),
|
||||||
|
ATL::CAtlList<COperation*>(sizeof(COperation*))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void COpList::Free()
|
||||||
|
{
|
||||||
|
POSITION pos;
|
||||||
|
|
||||||
|
for (pos = GetHeadPosition(); pos;) {
|
||||||
|
COperation *pOp = GetNext(pos);
|
||||||
|
COpList *pOpList = dynamic_cast<COpList*>(pOp);
|
||||||
|
|
||||||
|
if (pOpList) {
|
||||||
|
// Recursivelly free sublists.
|
||||||
|
pOpList->Free();
|
||||||
|
}
|
||||||
|
delete pOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpList::LoadFromFile(LPCTSTR pszFileName)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
ATL::CAtlFile fSequence;
|
||||||
|
|
||||||
|
hr = fSequence.Create(pszFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
// Load operation sequence.
|
||||||
|
return fSequence >> *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpList::SaveToFile(LPCTSTR pszFileName) const
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
ATL::CAtlFile fSequence;
|
||||||
|
|
||||||
|
hr = fSequence.Create(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
// Save execute sequence to file.
|
||||||
|
hr = fSequence << *this;
|
||||||
|
fSequence.Close();
|
||||||
|
|
||||||
|
if (FAILED(hr)) ::DeleteFile(pszFileName);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpList::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
POSITION pos;
|
||||||
|
HRESULT hr;
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(3);
|
||||||
|
|
||||||
|
// Tell the installer to use explicit progress messages.
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, 1);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, 1);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 3, 0);
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg);
|
||||||
|
|
||||||
|
// Prepare hRecordProg for progress messages.
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, 2);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 3, 0);
|
||||||
|
|
||||||
|
for (pos = GetHeadPosition(); pos;) {
|
||||||
|
COperation *pOp = GetNext(pos);
|
||||||
|
|
||||||
|
hr = pOp->Execute(pSession);
|
||||||
|
if (!pSession->m_bContinueOnError && FAILED(hr)) {
|
||||||
|
// Operation failed. Its Execute() method should have sent error message to Installer.
|
||||||
|
// Therefore, just quit here.
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, pOp->m_iTicks);
|
||||||
|
if (::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL)
|
||||||
|
return AtlHresultFromWin32(ERROR_INSTALL_USEREXIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, m_iTicks);
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CSession
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
CSession::CSession() :
|
||||||
|
m_bContinueOnError(FALSE),
|
||||||
|
m_bRollbackEnabled(FALSE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSession::~CSession()
|
||||||
|
{
|
||||||
|
m_olRollback.Free();
|
||||||
|
m_olCommit.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace MSICA
|
1429
MSICALib.h
Normal file
1429
MSICALib.h
Normal file
File diff suppressed because it is too large
Load Diff
135
MSICALib.vcxproj
Normal file
135
MSICALib.vcxproj
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="MSICALib.cpp" />
|
||||||
|
<ClCompile Include="FileOp.cpp" />
|
||||||
|
<ClCompile Include="TSOp.cpp" />
|
||||||
|
<ClCompile Include="RegOp.cpp" />
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="MSICALib.h" />
|
||||||
|
<ClInclude Include="stdafx.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="res\en_GB.po" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{8552EE55-177E-4F51-B51B-BAF7D6462CDE}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>MSICALib</RootNamespace>
|
||||||
|
<ProjectName>MSICALib</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<UseOfAtl>Static</UseOfAtl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<UseOfAtl>Static</UseOfAtl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<UseOfAtl>Static</UseOfAtl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<UseOfAtl>Static</UseOfAtl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\rcxgettext.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\include\common.props" />
|
||||||
|
<Import Project="..\include\Win32.props" />
|
||||||
|
<Import Project="..\include\Release.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\include\common.props" />
|
||||||
|
<Import Project="..\include\Win32.props" />
|
||||||
|
<Import Project="..\include\Debug.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\include\common.props" />
|
||||||
|
<Import Project="..\include\x64.props" />
|
||||||
|
<Import Project="..\include\Release.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\include\common.props" />
|
||||||
|
<Import Project="..\include\x64.props" />
|
||||||
|
<Import Project="..\include\Debug.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile />
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile />
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile />
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
<ClCompile />
|
||||||
|
<ClCompile />
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile />
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
<ClCompile />
|
||||||
|
<ClCompile />
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
47
MSICALib.vcxproj.filters
Normal file
47
MSICALib.vcxproj.filters
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="MSICALib.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="FileOp.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="TSOp.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="RegOp.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="MSICALib.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="stdafx.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="res\en_GB.po">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
724
RegOp.cpp
Normal file
724
RegOp.cpp
Normal file
@ -0,0 +1,724 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace MSICA {
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegKeySingle
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegKeySingle::COpRegKeySingle(HKEY hKeyRoot, LPCWSTR pszKeyName, int iTicks) :
|
||||||
|
m_hKeyRoot(hKeyRoot),
|
||||||
|
COpTypeSingleString(pszKeyName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegKeySrcDst
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegKeySrcDst::COpRegKeySrcDst(HKEY hKeyRoot, LPCWSTR pszKeyNameSrc, LPCWSTR pszKeyNameDst, int iTicks) :
|
||||||
|
m_hKeyRoot(hKeyRoot),
|
||||||
|
COpTypeSrcDstString(pszKeyNameSrc, pszKeyNameDst, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegKeyCreate
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegKeyCreate::COpRegKeyCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, int iTicks) : COpRegKeySingle(hKeyRoot, pszKeyName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRegKeyCreate::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
REGSAM samAdditional = 0;
|
||||||
|
ATL::CAtlStringW sPartialName;
|
||||||
|
int iStart = 0;
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (IsWow64Process()) {
|
||||||
|
// 32-bit processes run as WOW64 should use 64-bit registry too.
|
||||||
|
samAdditional |= KEY_WOW64_64KEY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HKEY hKey;
|
||||||
|
|
||||||
|
int iStartNext = m_sValue.Find(L'\\', iStart);
|
||||||
|
if (iStartNext >= 0)
|
||||||
|
sPartialName.SetString(m_sValue, iStartNext);
|
||||||
|
else
|
||||||
|
sPartialName = m_sValue;
|
||||||
|
|
||||||
|
// Try to open the key, to see if it exists.
|
||||||
|
lResult = ::RegOpenKeyExW(m_hKeyRoot, sPartialName, 0, KEY_ENUMERATE_SUB_KEYS | samAdditional, &hKey);
|
||||||
|
if (lResult == ERROR_FILE_NOT_FOUND) {
|
||||||
|
// The key doesn't exist yet. Create it.
|
||||||
|
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Order rollback action to delete the key. ::RegCreateEx() might create a key but return failure.
|
||||||
|
pSession->m_olRollback.AddHead(new COpRegKeyDelete(m_hKeyRoot, sPartialName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the key.
|
||||||
|
lResult = ::RegCreateKeyExW(m_hKeyRoot, sPartialName, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ENUMERATE_SUB_KEYS | samAdditional, NULL, &hKey, NULL);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
} else if (lResult == ERROR_SUCCESS) {
|
||||||
|
// This key already exists. Release its handle and continue.
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (iStartNext < 0) break;
|
||||||
|
iStart = iStartNext + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lResult == ERROR_SUCCESS)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(4);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_CREATE_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 4, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegKeyCopy
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegKeyCopy::COpRegKeyCopy(HKEY hKeyRoot, LPCWSTR pszKeyNameSrc, LPCWSTR pszKeyNameDst, int iTicks) : COpRegKeySrcDst(hKeyRoot, pszKeyNameSrc, pszKeyNameDst, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRegKeyCopy::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
REGSAM samAdditional = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Delete existing destination key first.
|
||||||
|
// Since deleting registry key is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it.
|
||||||
|
// Don't worry, COpRegKeyDelete::Execute() returns S_OK if key doesn't exist.
|
||||||
|
COpRegKeyDelete opDelete(m_hKeyRoot, m_sValue2);
|
||||||
|
HRESULT hr = opDelete.Execute(pSession);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (IsWow64Process()) {
|
||||||
|
// 32-bit processes run as WOW64 should use 64-bit registry too.
|
||||||
|
samAdditional |= KEY_WOW64_64KEY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Order rollback action to delete the destination key.
|
||||||
|
pSession->m_olRollback.AddHead(new COpRegKeyDelete(m_hKeyRoot, m_sValue2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the registry key.
|
||||||
|
lResult = CopyKeyRecursively(m_hKeyRoot, m_sValue1, m_sValue2, samAdditional);
|
||||||
|
if (lResult == ERROR_SUCCESS)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(5);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_COPY_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue1 );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 4, m_sValue2 );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 5, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LONG COpRegKeyCopy::CopyKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyNameSrc, LPCWSTR pszKeyNameDst, REGSAM samAdditional)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
HKEY hKeySrc, hKeyDst;
|
||||||
|
|
||||||
|
// Open source key.
|
||||||
|
lResult = ::RegOpenKeyExW(hKeyRoot, pszKeyNameSrc, 0, READ_CONTROL | KEY_READ | samAdditional, &hKeySrc);
|
||||||
|
if (lResult != ERROR_SUCCESS) return lResult;
|
||||||
|
|
||||||
|
{
|
||||||
|
DWORD dwSecurityDescriptorSize, dwClassLen = MAX_PATH;
|
||||||
|
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
|
||||||
|
LPWSTR pszClass = new WCHAR[dwClassLen];
|
||||||
|
|
||||||
|
// Get source key class length and security descriptor size.
|
||||||
|
lResult = ::RegQueryInfoKeyW(hKeySrc, pszClass, &dwClassLen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSecurityDescriptorSize, NULL);
|
||||||
|
if (lResult != ERROR_SUCCESS) {
|
||||||
|
delete [] pszClass;
|
||||||
|
return lResult;
|
||||||
|
}
|
||||||
|
pszClass[dwClassLen] = 0;
|
||||||
|
|
||||||
|
// Get source key security descriptor.
|
||||||
|
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(new BYTE[dwSecurityDescriptorSize]);
|
||||||
|
lResult = ::RegGetKeySecurity(hKeySrc, DACL_SECURITY_INFORMATION, sa.lpSecurityDescriptor, &dwSecurityDescriptorSize);
|
||||||
|
if (lResult != ERROR_SUCCESS) {
|
||||||
|
delete [] (LPBYTE)(sa.lpSecurityDescriptor);
|
||||||
|
delete [] pszClass;
|
||||||
|
return lResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new destination key of the same class and security.
|
||||||
|
lResult = ::RegCreateKeyExW(hKeyRoot, pszKeyNameDst, 0, pszClass, REG_OPTION_NON_VOLATILE, KEY_WRITE | samAdditional, &sa, &hKeyDst, NULL);
|
||||||
|
delete [] (LPBYTE)(sa.lpSecurityDescriptor);
|
||||||
|
delete [] pszClass;
|
||||||
|
if (lResult != ERROR_SUCCESS) return lResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy subkey recursively.
|
||||||
|
return CopyKeyRecursively(hKeySrc, hKeyDst, samAdditional);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LONG COpRegKeyCopy::CopyKeyRecursively(HKEY hKeySrc, HKEY hKeyDst, REGSAM samAdditional)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
DWORD dwMaxSubKeyLen, dwMaxValueNameLen, dwMaxClassLen, dwMaxDataSize, dwIndex;
|
||||||
|
LPWSTR pszName, pszClass;
|
||||||
|
LPBYTE lpData;
|
||||||
|
|
||||||
|
// Query the source key.
|
||||||
|
lResult = ::RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, NULL, &dwMaxSubKeyLen, &dwMaxClassLen, NULL, &dwMaxValueNameLen, &dwMaxDataSize, NULL, NULL);
|
||||||
|
if (lResult != ERROR_SUCCESS) return lResult;
|
||||||
|
|
||||||
|
// Copy values first.
|
||||||
|
dwMaxValueNameLen++;
|
||||||
|
pszName = new WCHAR[dwMaxValueNameLen];
|
||||||
|
lpData = new BYTE[dwMaxDataSize];
|
||||||
|
for (dwIndex = 0; ; dwIndex++) {
|
||||||
|
DWORD dwNameLen = dwMaxValueNameLen, dwType, dwValueSize = dwMaxDataSize;
|
||||||
|
|
||||||
|
// Read value.
|
||||||
|
lResult = ::RegEnumValueW(hKeySrc, dwIndex, pszName, &dwNameLen, NULL, &dwType, lpData, &dwValueSize);
|
||||||
|
if (lResult == ERROR_NO_MORE_ITEMS) {
|
||||||
|
lResult = ERROR_SUCCESS;
|
||||||
|
break;
|
||||||
|
} else if (lResult != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Save value.
|
||||||
|
lResult = ::RegSetValueExW(hKeyDst, pszName, 0, dwType, lpData, dwValueSize);
|
||||||
|
if (lResult != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete [] lpData;
|
||||||
|
delete [] pszName;
|
||||||
|
if (lResult != ERROR_SUCCESS) return lResult;
|
||||||
|
|
||||||
|
// Iterate over all subkeys and copy them.
|
||||||
|
dwMaxSubKeyLen++;
|
||||||
|
pszName = new WCHAR[dwMaxSubKeyLen];
|
||||||
|
dwMaxClassLen++;
|
||||||
|
pszClass = new WCHAR[dwMaxClassLen];
|
||||||
|
for (dwIndex = 0; ; dwIndex++) {
|
||||||
|
DWORD dwNameLen = dwMaxSubKeyLen, dwClassLen = dwMaxClassLen;
|
||||||
|
HKEY hKeySrcSub, hKeyDstSub;
|
||||||
|
|
||||||
|
// Read subkey.
|
||||||
|
lResult = ::RegEnumKeyExW(hKeySrc, dwIndex, pszName, &dwNameLen, NULL, pszClass, &dwClassLen, NULL);
|
||||||
|
if (lResult == ERROR_NO_MORE_ITEMS) {
|
||||||
|
lResult = ERROR_SUCCESS;
|
||||||
|
break;
|
||||||
|
} else if (lResult != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Open source subkey.
|
||||||
|
lResult = ::RegOpenKeyExW(hKeySrc, pszName, 0, READ_CONTROL | KEY_READ | samAdditional, &hKeySrcSub);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
|
||||||
|
{
|
||||||
|
DWORD dwSecurityDescriptorSize;
|
||||||
|
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
|
||||||
|
|
||||||
|
// Get source subkey security descriptor size.
|
||||||
|
lResult = ::RegQueryInfoKeyW(hKeySrcSub, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSecurityDescriptorSize, NULL);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
|
||||||
|
// Get source subkey security descriptor.
|
||||||
|
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(new BYTE[dwSecurityDescriptorSize]);
|
||||||
|
lResult = ::RegGetKeySecurity(hKeySrc, DACL_SECURITY_INFORMATION, sa.lpSecurityDescriptor, &dwSecurityDescriptorSize);
|
||||||
|
if (lResult != ERROR_SUCCESS) {
|
||||||
|
delete [] (LPBYTE)(sa.lpSecurityDescriptor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new destination subkey of the same class and security.
|
||||||
|
lResult = ::RegCreateKeyExW(hKeyDst, pszName, 0, pszClass, REG_OPTION_NON_VOLATILE, KEY_WRITE | samAdditional, &sa, &hKeyDstSub, NULL);
|
||||||
|
delete [] (LPBYTE)(sa.lpSecurityDescriptor);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy subkey recursively.
|
||||||
|
lResult = CopyKeyRecursively(hKeySrcSub, hKeyDstSub, samAdditional);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
}
|
||||||
|
delete [] pszClass;
|
||||||
|
delete [] pszName;
|
||||||
|
|
||||||
|
return lResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegKeyDelete
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegKeyDelete::COpRegKeyDelete(HKEY hKey, LPCWSTR pszKeyName, int iTicks) : COpRegKeySingle(hKey, pszKeyName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRegKeyDelete::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
HKEY hKey;
|
||||||
|
REGSAM samAdditional = 0;
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (IsWow64Process()) {
|
||||||
|
// 32-bit processes run as WOW64 should use 64-bit registry too.
|
||||||
|
samAdditional |= KEY_WOW64_64KEY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Probe to see if the key exists.
|
||||||
|
lResult = ::RegOpenKeyExW(m_hKeyRoot, m_sValue, 0, DELETE | samAdditional, &hKey);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Make a backup of the key first.
|
||||||
|
ATL::CAtlStringW sBackupName;
|
||||||
|
UINT uiCount = 0;
|
||||||
|
int iLength = m_sValue.GetLength();
|
||||||
|
|
||||||
|
// Trim trailing backslashes.
|
||||||
|
while (iLength && m_sValue.GetAt(iLength - 1) == L'\\') iLength--;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HKEY hKey;
|
||||||
|
sBackupName.Format(L"%.*ls (orig %u)", iLength, (LPCWSTR)m_sValue, ++uiCount);
|
||||||
|
lResult = ::RegOpenKeyExW(m_hKeyRoot, sBackupName, 0, KEY_ENUMERATE_SUB_KEYS | samAdditional, &hKey);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
if (lResult == ERROR_FILE_NOT_FOUND) {
|
||||||
|
// Since copying registry key is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it.
|
||||||
|
COpRegKeyCopy opCopy(m_hKeyRoot, m_sValue, sBackupName);
|
||||||
|
HRESULT hr = opCopy.Execute(pSession);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
// Order rollback action to restore the key from backup copy.
|
||||||
|
pSession->m_olRollback.AddHead(new COpRegKeyCopy(m_hKeyRoot, sBackupName, m_sValue));
|
||||||
|
|
||||||
|
// Order commit action to delete backup copy.
|
||||||
|
pSession->m_olCommit.AddTail(new COpRegKeyDelete(m_hKeyRoot, sBackupName));
|
||||||
|
} else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(4);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_PROBING_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, sBackupName );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 4, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the registry key.
|
||||||
|
lResult = DeleteKeyRecursively(m_hKeyRoot, m_sValue, samAdditional);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(4);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_DELETE_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 4, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LONG COpRegKeyDelete::DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM samAdditional)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
LONG lResult;
|
||||||
|
|
||||||
|
// Open the key.
|
||||||
|
lResult = ::RegOpenKeyExW(hKeyRoot, pszKeyName, 0, DELETE | KEY_READ | samAdditional, &hKey);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
DWORD dwMaxSubKeyLen;
|
||||||
|
|
||||||
|
// Determine the largest subkey name.
|
||||||
|
lResult = ::RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
LPWSTR pszSubKeyName;
|
||||||
|
|
||||||
|
// Prepare buffer to hold the subkey names (including zero terminator).
|
||||||
|
dwMaxSubKeyLen++;
|
||||||
|
pszSubKeyName = new WCHAR[dwMaxSubKeyLen];
|
||||||
|
if (pszSubKeyName) {
|
||||||
|
DWORD dwIndex;
|
||||||
|
|
||||||
|
// Iterate over all subkeys and delete them. Skip failed.
|
||||||
|
for (dwIndex = 0; ;) {
|
||||||
|
DWORD dwNameLen = dwMaxSubKeyLen;
|
||||||
|
lResult = ::RegEnumKeyExW(hKey, dwIndex, pszSubKeyName, &dwNameLen, NULL, NULL, NULL, NULL);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
lResult = DeleteKeyRecursively(hKey, pszSubKeyName, samAdditional);
|
||||||
|
if (lResult != ERROR_SUCCESS)
|
||||||
|
dwIndex++;
|
||||||
|
} else if (lResult == ERROR_NO_MORE_ITEMS) {
|
||||||
|
lResult = ERROR_SUCCESS;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
dwIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] pszSubKeyName;
|
||||||
|
} else
|
||||||
|
lResult = ERROR_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
|
||||||
|
// Finally try to delete the key.
|
||||||
|
lResult = ::RegDeleteKeyW(hKeyRoot, pszKeyName);
|
||||||
|
} else if (lResult == ERROR_FILE_NOT_FOUND) {
|
||||||
|
// The key doesn't exist. Not really an error in this case.
|
||||||
|
lResult = ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegValueSingle
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegValueSingle::COpRegValueSingle(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, int iTicks) :
|
||||||
|
m_sValueName(pszValueName),
|
||||||
|
COpRegKeySingle(hKeyRoot, pszKeyName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegValueSrcDst
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegValueSrcDst::COpRegValueSrcDst(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueNameSrc, LPCWSTR pszValueNameDst, int iTicks) :
|
||||||
|
m_sValueName1(pszValueNameSrc),
|
||||||
|
m_sValueName2(pszValueNameDst),
|
||||||
|
COpRegKeySingle(hKeyRoot, pszKeyName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegValueCreate
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegValueCreate::COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, int iTicks) :
|
||||||
|
m_dwType(REG_NONE),
|
||||||
|
COpRegValueSingle(hKeyRoot, pszKeyName, pszValueName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COpRegValueCreate::COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, DWORD dwData, int iTicks) :
|
||||||
|
m_dwType(REG_DWORD),
|
||||||
|
m_dwData(dwData),
|
||||||
|
COpRegValueSingle(hKeyRoot, pszKeyName, pszValueName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COpRegValueCreate::COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, LPCVOID lpData, SIZE_T nSize, int iTicks) :
|
||||||
|
m_dwType(REG_BINARY),
|
||||||
|
COpRegValueSingle(hKeyRoot, pszKeyName, pszValueName, iTicks)
|
||||||
|
{
|
||||||
|
m_binData.SetCount(nSize);
|
||||||
|
memcpy(m_binData.GetData(), lpData, nSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COpRegValueCreate::COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, LPCWSTR pszData, int iTicks) :
|
||||||
|
m_dwType(REG_SZ),
|
||||||
|
m_sData(pszData),
|
||||||
|
COpRegValueSingle(hKeyRoot, pszKeyName, pszValueName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COpRegValueCreate::COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, DWORDLONG qwData, int iTicks) :
|
||||||
|
m_dwType(REG_QWORD),
|
||||||
|
m_qwData(qwData),
|
||||||
|
COpRegValueSingle(hKeyRoot, pszKeyName, pszValueName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRegValueCreate::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
REGSAM sam = KEY_QUERY_VALUE | STANDARD_RIGHTS_WRITE | KEY_SET_VALUE;
|
||||||
|
HKEY hKey;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Delete existing value first.
|
||||||
|
// Since deleting registry value is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it.
|
||||||
|
// Don't worry, COpRegValueDelete::Execute() returns S_OK if key doesn't exist.
|
||||||
|
COpRegValueDelete opDelete(m_hKeyRoot, m_sValue, m_sValueName);
|
||||||
|
HRESULT hr = opDelete.Execute(pSession);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (IsWow64Process()) {
|
||||||
|
// 32-bit processes run as WOW64 should use 64-bit registry too.
|
||||||
|
sam |= KEY_WOW64_64KEY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Open the key.
|
||||||
|
lResult = ::RegOpenKeyExW(m_hKeyRoot, m_sValue, 0, sam, &hKey);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Order rollback action to delete the value.
|
||||||
|
pSession->m_olRollback.AddHead(new COpRegValueDelete(m_hKeyRoot, m_sValue, m_sValueName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the registry value.
|
||||||
|
switch (m_dwType) {
|
||||||
|
case REG_SZ:
|
||||||
|
case REG_EXPAND_SZ:
|
||||||
|
case REG_LINK:
|
||||||
|
lResult = ::RegSetValueExW(hKey, m_sValueName, 0, m_dwType, (const BYTE*)(LPCWSTR)m_sData, (m_sData.GetLength() + 1) * sizeof(WCHAR)); break;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_BINARY:
|
||||||
|
lResult = ::RegSetValueExW(hKey, m_sValueName, 0, m_dwType, m_binData.GetData(), (DWORD)m_binData.GetCount() * sizeof(BYTE)); break;
|
||||||
|
|
||||||
|
case REG_DWORD_LITTLE_ENDIAN:
|
||||||
|
case REG_DWORD_BIG_ENDIAN:
|
||||||
|
lResult = ::RegSetValueExW(hKey, m_sValueName, 0, m_dwType, (const BYTE*)&m_dwData, sizeof(DWORD)); break;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_MULTI_SZ:
|
||||||
|
lResult = ::RegSetValueExW(hKey, m_sValueName, 0, m_dwType, (const BYTE*)m_szData.GetData(), (DWORD)m_szData.GetCount() * sizeof(WCHAR)); break;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REG_QWORD_LITTLE_ENDIAN:
|
||||||
|
lResult = ::RegSetValueExW(hKey, m_sValueName, 0, m_dwType, (const BYTE*)&m_qwData, sizeof(DWORDLONG)); break;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
lResult = ERROR_UNSUPPORTED_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lResult == ERROR_SUCCESS)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(5);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_SETVALUE_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 4, m_sValueName );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 5, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegValueCopy
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegValueCopy::COpRegValueCopy(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueNameSrc, LPCWSTR pszValueNameDst, int iTicks) : COpRegValueSrcDst(hKeyRoot, pszKeyName, pszValueNameSrc, pszValueNameDst, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRegValueCopy::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
REGSAM sam = KEY_QUERY_VALUE | KEY_SET_VALUE;
|
||||||
|
HKEY hKey;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Delete existing destination value first.
|
||||||
|
// Since deleting registry value is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it.
|
||||||
|
// Don't worry, COpRegValueDelete::Execute() returns S_OK if key doesn't exist.
|
||||||
|
COpRegValueDelete opDelete(m_hKeyRoot, m_sValue, m_sValueName2);
|
||||||
|
HRESULT hr = opDelete.Execute(pSession);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (IsWow64Process()) {
|
||||||
|
// 32-bit processes run as WOW64 should use 64-bit registry too.
|
||||||
|
sam |= KEY_WOW64_64KEY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Open the key.
|
||||||
|
lResult = ::RegOpenKeyExW(m_hKeyRoot, m_sValue, 0, sam, &hKey);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
DWORD dwType, dwSize;
|
||||||
|
|
||||||
|
// Query the source registry value size.
|
||||||
|
lResult = ::RegQueryValueExW(hKey, m_sValueName1, 0, NULL, NULL, &dwSize);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
LPBYTE lpData = new BYTE[dwSize];
|
||||||
|
// Read the source registry value.
|
||||||
|
lResult = ::RegQueryValueExW(hKey, m_sValueName1, 0, &dwType, lpData, &dwSize);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Order rollback action to delete the destination copy.
|
||||||
|
pSession->m_olRollback.AddHead(new COpRegValueDelete(m_hKeyRoot, m_sValue, m_sValueName2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the value to destination.
|
||||||
|
lResult = ::RegSetValueExW(hKey, m_sValueName2, 0, dwType, lpData, dwSize);
|
||||||
|
}
|
||||||
|
delete [] lpData;
|
||||||
|
}
|
||||||
|
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lResult == ERROR_SUCCESS)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(6);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_COPYVALUE_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 4, m_sValueName1 );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 5, m_sValueName2 );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 6, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// COpRegValueDelete
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
COpRegValueDelete::COpRegValueDelete(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, int iTicks) : COpRegValueSingle(hKeyRoot, pszKeyName, pszValueName, iTicks)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT COpRegValueDelete::Execute(CSession *pSession)
|
||||||
|
{
|
||||||
|
LONG lResult;
|
||||||
|
REGSAM sam = KEY_QUERY_VALUE | KEY_SET_VALUE;
|
||||||
|
HKEY hKey;
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (IsWow64Process()) {
|
||||||
|
// 32-bit processes run as WOW64 should use 64-bit registry too.
|
||||||
|
sam |= KEY_WOW64_64KEY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Open the key.
|
||||||
|
lResult = ::RegOpenKeyExW(m_hKeyRoot, m_sValue, 0, sam, &hKey);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
DWORD dwType;
|
||||||
|
|
||||||
|
// See if the value exists at all.
|
||||||
|
lResult = ::RegQueryValueExW(hKey, m_sValueName, 0, &dwType, NULL, NULL);
|
||||||
|
if (lResult == ERROR_SUCCESS) {
|
||||||
|
if (pSession->m_bRollbackEnabled) {
|
||||||
|
// Make a backup of the value first.
|
||||||
|
ATL::CAtlStringW sBackupName;
|
||||||
|
UINT uiCount = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
sBackupName.Format(L"%ls (orig %u)", (LPCWSTR)m_sValueName, ++uiCount);
|
||||||
|
lResult = ::RegQueryValueExW(hKey, sBackupName, 0, &dwType, NULL, NULL);
|
||||||
|
if (lResult != ERROR_SUCCESS) break;
|
||||||
|
}
|
||||||
|
if (lResult == ERROR_FILE_NOT_FOUND) {
|
||||||
|
// Since copying registry value is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it.
|
||||||
|
COpRegValueCopy opCopy(m_hKeyRoot, m_sValue, m_sValueName, sBackupName);
|
||||||
|
HRESULT hr = opCopy.Execute(pSession);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order rollback action to restore the key from backup copy.
|
||||||
|
pSession->m_olRollback.AddHead(new COpRegValueCopy(m_hKeyRoot, m_sValue, sBackupName, m_sValueName));
|
||||||
|
|
||||||
|
// Order commit action to delete backup copy.
|
||||||
|
pSession->m_olCommit.AddTail(new COpRegValueDelete(m_hKeyRoot, m_sValue, sBackupName));
|
||||||
|
} else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(5);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_PROBINGVAL_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, sBackupName );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 4, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the registry value.
|
||||||
|
lResult = ::RegDeleteValueW(hKey, m_sValueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
::RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND)
|
||||||
|
return S_OK;
|
||||||
|
else {
|
||||||
|
PMSIHANDLE hRecordProg = ::MsiCreateRecord(5);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_DELETEVALUE_FAILED);
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 3, m_sValue );
|
||||||
|
::MsiRecordSetStringW(hRecordProg, 4, m_sValueName );
|
||||||
|
::MsiRecordSetInteger(hRecordProg, 5, lResult );
|
||||||
|
::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
|
||||||
|
return AtlHresultFromWin32(lResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace MSICA
|
56
msm/Makefile
Normal file
56
msm/Makefile
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
!INCLUDE "..\..\include\MSINast.mak"
|
||||||
|
|
||||||
|
MSM_IMA_LOKALIZACIJO=1
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Error
|
||||||
|
|
||||||
|
Vse :: \
|
||||||
|
"$(JEZIK).$(CFG).$(PLAT).Error-1.idt" \
|
||||||
|
"$(JEZIK).$(CFG).$(PLAT).Error-2.idt"
|
||||||
|
|
||||||
|
"$(JEZIK).$(CFG).$(PLAT).Error-1.idt" : "Makefile" "..\..\include\MSINast.mak"
|
||||||
|
-if exist $@ del /f /q $@
|
||||||
|
move /y << $@ > NUL
|
||||||
|
Error Message
|
||||||
|
i2 L0
|
||||||
|
Error Error
|
||||||
|
<<NOKEEP
|
||||||
|
|
||||||
|
"Sl.$(CFG).$(PLAT).Error-2.idtx" : "Makefile" "..\..\include\MSINast.mak"
|
||||||
|
-if exist $@ del /f /q $@
|
||||||
|
move /y << $@ > NUL
|
||||||
|
Error Message
|
||||||
|
i2 L0
|
||||||
|
1250 Error Error
|
||||||
|
2550 Pri odpiranju namestitvenega paketa je prišlo do napake. Obrnite se na svojo tehnièno službo.
|
||||||
|
2552 Pri pisanju v datoteko seznama opravil »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2560 Pri branju iz datoteke seznama opravil »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2553 Pri nastavljanju parametra »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2554 Pri brisanju datoteke »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2555 Pri premikanju datoteke »[2]« v »[3]« je prišlo do napake [4]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2556 Pri ustvarjanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2557 Pri brisanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2558 Pri o(ne)mogoèanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnièno službo.
|
||||||
|
2559 Pri kopiranju razporejenega opravila »[2]« v »[3]« je prišlo do napake [4]. Obrnite se na svojo tehnièno službo.
|
||||||
|
<<NOKEEP
|
||||||
|
|
||||||
|
"De.$(CFG).$(PLAT).Error-2.idt" : "Sl.$(CFG).$(PLAT).Error-2.idtx" "..\res\de_DE.po"
|
||||||
|
rcxgettext.exe idtp $@ $**
|
||||||
|
|
||||||
|
"En.$(CFG).$(PLAT).Error-2.idt" : "Sl.$(CFG).$(PLAT).Error-2.idtx" "..\res\en_GB.po"
|
||||||
|
rcxgettext.exe idtp $@ $**
|
||||||
|
|
||||||
|
"It.$(CFG).$(PLAT).Error-2.idt" : "Sl.$(CFG).$(PLAT).Error-2.idtx" "..\res\it_IT.po"
|
||||||
|
rcxgettext.exe idtp $@ $**
|
||||||
|
|
||||||
|
"Sl.$(CFG).$(PLAT).Error-2.idt" : "Sl.$(CFG).$(PLAT).Error-2.idtx"
|
||||||
|
copy /y $** $@ > NUL
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Izdelava modula MSM
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
!INCLUDE "..\..\AOsn\msm\MSM.mak"
|
100
res/en_GB.po
Normal file
100
res/en_GB.po
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: MSITSCA\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2013-06-07 21:16+0100\n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Last-Translator: Simon Rozman <simon.rozman@amebis.si>\n"
|
||||||
|
"Language-Team: Amebis, d. o. o., Kamnik <simon.rozman@amebis.si>\n"
|
||||||
|
"Language: en\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Poedit-SourceCharset: UTF-8\n"
|
||||||
|
"X-Poedit-KeywordsList: __\n"
|
||||||
|
"X-Poedit-Basepath: .\n"
|
||||||
|
"X-Generator: Poedit 1.5.5\n"
|
||||||
|
"X-Poedit-SearchPath-0: .\n"
|
||||||
|
"X-Poedit-SearchPath-1: ..\\msm\n"
|
||||||
|
|
||||||
|
# Privzeta kodna stran ANSI za ta jezik (desetiško)
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:3 ..\msm/Sl.DebugU.x64.Error-2.idtx:3
|
||||||
|
msgid "1250"
|
||||||
|
msgstr "1252"
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:6 ..\msm/Sl.DebugU.x64.Error-2.idtx:6
|
||||||
|
msgid ""
|
||||||
|
"Pri branju iz datoteke seznama opravil »[2]« je prišlo do napake [3]. "
|
||||||
|
"Obrnite se na svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] reading from \"[2]\" task list file. Please, contact your support "
|
||||||
|
"personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:8 ..\msm/Sl.DebugU.x64.Error-2.idtx:8
|
||||||
|
msgid ""
|
||||||
|
"Pri brisanju datoteke »[2]« je prišlo do napake [3]. Obrnite se na svojo "
|
||||||
|
"tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] deleting \"[2]\" file. Please, contact your support personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:11 ..\msm/Sl.DebugU.x64.Error-2.idtx:11
|
||||||
|
msgid ""
|
||||||
|
"Pri brisanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite "
|
||||||
|
"se na svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] deleting \"[2]\" scheduled task. Please, contact your support "
|
||||||
|
"personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:13 ..\msm/Sl.DebugU.x64.Error-2.idtx:13
|
||||||
|
msgid ""
|
||||||
|
"Pri kopiranju razporejenega opravila »[2]« v »[3]« je prišlo do napake [4]. "
|
||||||
|
"Obrnite se na svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [4] copying \"[2]\" scheduled task to \"[3]\". Please, contact your "
|
||||||
|
"support personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:7 ..\msm/Sl.DebugU.x64.Error-2.idtx:7
|
||||||
|
msgid ""
|
||||||
|
"Pri nastavljanju parametra »[2]« je prišlo do napake [3]. Obrnite se na "
|
||||||
|
"svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] setting \"[2]\" parameter. Please, contact your support personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:12 ..\msm/Sl.DebugU.x64.Error-2.idtx:12
|
||||||
|
msgid ""
|
||||||
|
"Pri o(ne)mogočanju razporejenega opravila »[2]« je prišlo do napake [3]. "
|
||||||
|
"Obrnite se na svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] enabling/disabling \"[2]\" scheduled task. Please, contact your "
|
||||||
|
"support personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:4 ..\msm/Sl.DebugU.x64.Error-2.idtx:4
|
||||||
|
msgid ""
|
||||||
|
"Pri odpiranju namestitvenega paketa je prišlo do napake. Obrnite se na svojo "
|
||||||
|
"tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error opening installation package. Please, contact your support personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:5 ..\msm/Sl.DebugU.x64.Error-2.idtx:5
|
||||||
|
msgid ""
|
||||||
|
"Pri pisanju v datoteko seznama opravil »[2]« je prišlo do napake [3]. "
|
||||||
|
"Obrnite se na svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] writing to \"[2]\" task list file. Please, contact your support "
|
||||||
|
"personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:9 ..\msm/Sl.DebugU.x64.Error-2.idtx:9
|
||||||
|
msgid ""
|
||||||
|
"Pri premikanju datoteke »[2]« v »[3]« je prišlo do napake [4]. Obrnite se na "
|
||||||
|
"svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [4] moving \"[2]\" file to \"[3]\". Please, contact your support "
|
||||||
|
"personnel."
|
||||||
|
|
||||||
|
#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:10 ..\msm/Sl.DebugU.x64.Error-2.idtx:10
|
||||||
|
msgid ""
|
||||||
|
"Pri ustvarjanju razporejenega opravila »[2]« je prišlo do napake [3]. "
|
||||||
|
"Obrnite se na svojo tehnično službo."
|
||||||
|
msgstr ""
|
||||||
|
"Error [3] creating \"[2]\" scheduled task. Please, contact your support "
|
||||||
|
"personnel."
|
1
stdafx.cpp
Normal file
1
stdafx.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "stdafx.h"
|
35
stdafx.h
Normal file
35
stdafx.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// stdafx.h : include file for standard system include files,
|
||||||
|
// or project specific include files that are used frequently,
|
||||||
|
// but are changed infrequently
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(_UNICODE) && !defined(UNICODE)
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(WIN32)
|
||||||
|
#define WIN32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STRICT
|
||||||
|
#define STRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
#define _WIN32_WINNT 0x0501 // Include Windows XP symbols
|
||||||
|
#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
|
||||||
|
//#define _ATL_APARTMENT_THREADED
|
||||||
|
//#define _ATL_NO_AUTOMATIC_NAMESPACE
|
||||||
|
//#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // Some CString constructors will be explicit
|
||||||
|
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include <atlfile.h>
|
||||||
|
#include <atlstr.h>
|
||||||
|
|
||||||
|
#include <msi.h>
|
||||||
|
#include <msiquery.h>
|
||||||
|
#include <mstask.h>
|
||||||
|
#include <taskschd.h>
|
||||||
|
|
||||||
|
#include "MSICALib.h"
|
Loading…
x
Reference in New Issue
Block a user