From 12a8cbd84e76e0f11fac772d6f2e508f123db3b1 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 26 Apr 2013 15:30:05 +0000 Subject: [PATCH] =?UTF-8?q?Dodal=20sem=20podporo=20za=20delo=20s=20klju?= =?UTF-8?q?=C4=8Di=20v=20registru.=20Ni=20=C5=A1e=20dokon=C4=8Dna.=20Vseen?= =?UTF-8?q?o=20uveljavljam,=20da=20bo=20na=20varnem.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 1 + AMSICA/AMSICALib/AMSICALib.vcxproj | 1 + AMSICA/AMSICALib/AMSICALib.vcxproj.filters | 3 + AMSICA/include/AMSICA.h | 195 ++++++++++++-- AMSICA/src/AMSICAFileOp.cpp | 14 +- AMSICA/src/AMSICATSOp.cpp | 4 +- AMSICA/src/MSICARegOp.cpp | 279 +++++++++++++++++++++ 7 files changed, 473 insertions(+), 24 deletions(-) create mode 100644 AMSICA/src/MSICARegOp.cpp diff --git a/.gitattributes b/.gitattributes index 642a25b..805532d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,6 +9,7 @@ AMSICA/res/en_GB.po -text AMSICA/src/AMSICA.cpp -text AMSICA/src/AMSICAFileOp.cpp -text AMSICA/src/AMSICATSOp.cpp -text +AMSICA/src/MSICARegOp.cpp -text AMSICA/src/StdAfx.cpp -text MSITSCA/L10N/sl_SI.po -text MSITSCA/MSITSCA.cpp -text diff --git a/AMSICA/AMSICALib/AMSICALib.vcxproj b/AMSICA/AMSICALib/AMSICALib.vcxproj index 6f5a095..d87fb92 100644 --- a/AMSICA/AMSICALib/AMSICALib.vcxproj +++ b/AMSICA/AMSICALib/AMSICALib.vcxproj @@ -38,6 +38,7 @@ + Create Create diff --git a/AMSICA/AMSICALib/AMSICALib.vcxproj.filters b/AMSICA/AMSICALib/AMSICALib.vcxproj.filters index a552fa5..00fbc92 100644 --- a/AMSICA/AMSICALib/AMSICALib.vcxproj.filters +++ b/AMSICA/AMSICALib/AMSICALib.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + diff --git a/AMSICA/include/AMSICA.h b/AMSICA/include/AMSICA.h index 2905241..611f020 100644 --- a/AMSICA/include/AMSICA.h +++ b/AMSICA/include/AMSICA.h @@ -26,11 +26,15 @@ //////////////////////////////////////////////////////////////////// -// Error codes (last unused 2561L) +// Error codes (next unused 2565L) //////////////////////////////////////////////////////////////////// -#define ERROR_INSTALL_DELETE_FAILED 2554L -#define ERROR_INSTALL_MOVE_FAILED 2555L +#define ERROR_INSTALL_FILE_DELETE_FAILED 2554L +#define ERROR_INSTALL_FILE_MOVE_FAILED 2555L +#define ERROR_INSTALL_REGKEY_CREATE_FAILED 2561L +#define ERROR_INSTALL_REGKEY_COPY_FAILED 2562L +#define ERROR_INSTALL_REGKEY_PROBING_FAILED 2563L +#define ERROR_INSTALL_REGKEY_DELETE_FAILED 2564L #define ERROR_INSTALL_TASK_CREATE_FAILED 2556L #define ERROR_INSTALL_TASK_DELETE_FAILED 2557L #define ERROR_INSTALL_TASK_ENABLE_FAILED 2558L @@ -83,8 +87,8 @@ class COpTypeSingleString : public COperation public: COpTypeSingleString(LPCWSTR pszValue = L"", int iTicks = 0); - friend inline HRESULT operator <<(ATL::CAtlFile &f, const AMSICA::COpTypeSingleString &op); - friend inline HRESULT operator >>(ATL::CAtlFile &f, AMSICA::COpTypeSingleString &op); + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeSingleString &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeSingleString &op); protected: ATL::CAtlStringW m_sValue; @@ -100,8 +104,8 @@ class COpTypeSrcDstString : public COperation public: COpTypeSrcDstString(LPCWSTR pszValue1 = L"", LPCWSTR pszValue2 = L"", int iTicks = 0); - friend inline HRESULT operator <<(ATL::CAtlFile &f, const AMSICA::COpTypeSrcDstString &op); - friend inline HRESULT operator >>(ATL::CAtlFile &f, AMSICA::COpTypeSrcDstString &op); + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeSrcDstString &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeSrcDstString &op); protected: ATL::CAtlStringW m_sValue1; @@ -118,8 +122,8 @@ class COpTypeBoolean : public COperation public: COpTypeBoolean(BOOL bValue = TRUE, int iTicks = 0); - friend inline HRESULT operator <<(ATL::CAtlFile &f, const AMSICA::COpTypeBoolean &op); - friend inline HRESULT operator >>(ATL::CAtlFile &f, AMSICA::COpTypeBoolean &op); + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeBoolean &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeBoolean &op); protected: BOOL m_bValue; @@ -162,6 +166,82 @@ public: }; +//////////////////////////////////////////////////////////////////////////// +// COpRegKeySingle +//////////////////////////////////////////////////////////////////////////// + +class COpRegKeySingle : public COpTypeSingleString +{ +public: + COpRegKeySingle(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", int iTicks = 0); + + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegKeySingle &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpRegKeySingle &op); + +protected: + HKEY m_hKeyRoot; +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegKeySrcDst +//////////////////////////////////////////////////////////////////////////// + +class COpRegKeySrcDst : public COpTypeSrcDstString +{ +public: + COpRegKeySrcDst(HKEY hKeyRoot = NULL, LPCWSTR pszKeyNameSrc = L"", LPCWSTR pszKeyNameDst = L"", int iTicks = 0); + + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegKeySrcDst &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpRegKeySrcDst &op); + +protected: + HKEY m_hKeyRoot; +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegKeyCreate +//////////////////////////////////////////////////////////////////////////// + +class COpRegKeyCreate : public COpRegKeySingle +{ +public: + COpRegKeyCreate(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", int iTicks = 0); + virtual HRESULT Execute(CSession *pSession); +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegKeyCopy +//////////////////////////////////////////////////////////////////////////// + +class COpRegKeyCopy : public COpRegKeySrcDst +{ +public: + COpRegKeyCopy(HKEY hKey = NULL, LPCWSTR pszKeyNameSrc = L"", LPCWSTR pszKeyNameDst = L"", int iTicks = 0); + virtual HRESULT Execute(CSession *pSession); + +private: + static LONG CopyKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyNameSrc, LPCWSTR pszKeyNameDst, REGSAM samAdditional); +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegKeyDelete +//////////////////////////////////////////////////////////////////////////// + +class COpRegKeyDelete : public COpRegKeySingle +{ +public: + COpRegKeyDelete(HKEY hKey = NULL, LPCWSTR pszKeyName = L"", int iTicks = 0); + virtual HRESULT Execute(CSession *pSession); + +private: + static LONG DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM sam); +}; + + //////////////////////////////////////////////////////////////////////////// // COpTaskCreate //////////////////////////////////////////////////////////////////////////// @@ -176,8 +256,8 @@ public: UINT SetFromRecord(MSIHANDLE hInstall, MSIHANDLE hRecord); UINT SetTriggersFromView(MSIHANDLE hView); - friend inline HRESULT operator <<(ATL::CAtlFile &f, const AMSICA::COpTaskCreate &op); - friend inline HRESULT operator >>(ATL::CAtlFile &f, AMSICA::COpTaskCreate &op); + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpTaskCreate &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpTaskCreate &op); protected: ATL::CAtlStringW m_sApplicationName; @@ -665,7 +745,7 @@ inline HRESULT operator >>(ATL::CAtlFile &f, TASK_TRIGGER &ttData) } -inline HRESULT operator <<(ATL::CAtlFile &f, const AMSICA::COperation &op) +inline HRESULT operator <<(ATL::CAtlFile &f, const COperation &op) { return f << op.m_iTicks; } @@ -740,8 +820,8 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeBoolean &op) inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeBoolean &op) { - int iValue; HRESULT hr; + int iValue; hr = f >> (COperation &)op; if (FAILED(hr)) return hr; @@ -754,12 +834,59 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeBoolean &op) } + +inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegKeySingle &op) +{ + HRESULT hr; + + hr = f << (const COpTypeSingleString &)op; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_hKeyRoot); if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, COpRegKeySingle &op) +{ + HRESULT hr; + int iValue; + + hr = f >> (COpTypeSingleString &)op; if (FAILED(hr)) return hr; + hr = f >> iValue; if (FAILED(hr)) return hr; op.m_hKeyRoot = (HKEY)iValue; + + return S_OK; +} + + +inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegKeySrcDst &op) +{ + HRESULT hr; + + hr = f << (const COpTypeSrcDstString &)op; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_hKeyRoot); if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, COpRegKeySrcDst &op) +{ + HRESULT hr; + int iValue; + + hr = f >> (COpTypeSrcDstString &)op; if (FAILED(hr)) return hr; + hr = f >> iValue; if (FAILED(hr)) return hr; op.m_hKeyRoot = (HKEY)iValue; + + return S_OK; +} + + inline HRESULT operator <<(ATL::CAtlFile &f, const COpTaskCreate &op) { HRESULT hr; POSITION pos; - hr = f << (const COpTypeSingleString&)op; if (FAILED(hr)) return hr; + hr = f << (const COpTypeSingleString&)op; if (FAILED(hr)) return hr; hr = f << op.m_sApplicationName; if (FAILED(hr)) return hr; hr = f << op.m_sParameters; if (FAILED(hr)) return hr; hr = f << op.m_sWorkingDirectory; if (FAILED(hr)) return hr; @@ -786,7 +913,7 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpTaskCreate &op) HRESULT hr; DWORD dwValue; - hr = f >> (COpTypeSingleString&)op; if (FAILED(hr)) return hr; + hr = f >> (COpTypeSingleString&)op; if (FAILED(hr)) return hr; hr = f >> op.m_sApplicationName; if (FAILED(hr)) return hr; hr = f >> op.m_sParameters; if (FAILED(hr)) return hr; hr = f >> op.m_sWorkingDirectory; if (FAILED(hr)) return hr; @@ -934,6 +1061,44 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpList &list) } +//////////////////////////////////////////////////////////////////// +// Inline Functions +//////////////////////////////////////////////////////////////////// + + +inline BOOL IsWow64Process() +{ +#ifndef _WIN64 + // Find IsWow64Process() address in KERNEL32.DLL. + BOOL (WINAPI *_IsWow64Process)(__in HANDLE hProcess, __out PBOOL Wow64Process) = (BOOL(WINAPI*)(__in HANDLE, __out PBOOL))::GetProcAddress(::GetModuleHandle(_T("KERNEL32.DLL")), "IsWow64Process"); + + // See if our 32-bit process is running in 64-bit environment. + if (_IsWow64Process) { + BOOL bResult; + + // See, what IsWow64Process() says about current process. + if (_IsWow64Process(::GetCurrentProcess(), &bResult)) { + // Return result. + return bResult; + } else { + // IsWow64Process() returned an error. Assume, the process is not WOW64. + return FALSE; + } + } else { + // This KERNEL32.DLL doesn't know IsWow64Process().Definitely not a WOW64 process. + return FALSE; + } +#else + // 64-bit processes are never run as WOW64. + return FALSE; +#endif +} + +#ifndef _WIN64 +#endif + + + //////////////////////////////////////////////////////////////////////////// // Inline methods //////////////////////////////////////////////////////////////////////////// diff --git a/AMSICA/src/AMSICAFileOp.cpp b/AMSICA/src/AMSICAFileOp.cpp index b9b8b1b..f4ac5e2 100644 --- a/AMSICA/src/AMSICAFileOp.cpp +++ b/AMSICA/src/AMSICAFileOp.cpp @@ -43,9 +43,9 @@ HRESULT COpFileDelete::Execute(CSession *pSession) return S_OK; else { PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_DELETE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, dwError ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_FILE_DELETE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 3, dwError ) == ERROR_SUCCESS); ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); return AtlHresultFromWin32(dwError); } @@ -78,10 +78,10 @@ HRESULT COpFileMove::Execute(CSession *pSession) return S_OK; } else { PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_MOVE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue1 ) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue2 ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 4, dwError ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_FILE_MOVE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue1 ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue2 ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 4, dwError ) == ERROR_SUCCESS); ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); return AtlHresultFromWin32(dwError); } diff --git a/AMSICA/src/AMSICATSOp.cpp b/AMSICA/src/AMSICATSOp.cpp index 50950c2..3b816ce 100644 --- a/AMSICA/src/AMSICATSOp.cpp +++ b/AMSICA/src/AMSICATSOp.cpp @@ -45,8 +45,8 @@ HRESULT COpTaskCreate::Execute(CSession *pSession) // Delete existing task first. // Since task deleting 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, COpTaskDelete::Execute() returns S_OK if task doesn't exist. - COpTaskDelete opDeleteTask(m_sValue); - hr = opDeleteTask.Execute(pSession); + COpTaskDelete opDelete(m_sValue); + hr = opDelete.Execute(pSession); if (FAILED(hr)) goto finish; } diff --git a/AMSICA/src/MSICARegOp.cpp b/AMSICA/src/MSICARegOp.cpp new file mode 100644 index 0000000..90020b5 --- /dev/null +++ b/AMSICA/src/MSICARegOp.cpp @@ -0,0 +1,279 @@ +#include "StdAfx.h" + + +namespace AMSICA { + + +//////////////////////////////////////////////////////////////////////////// +// 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) +{ + assert(pSession); + LONG lResult; + REGSAM samAdditional = 0; + ATL::CAtlStringW sPartialName; + int iStart = 0; + + assert(0); // TODO: Preizkusi ta del kode. + +#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; + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + } else if (lResult == ERROR_SUCCESS) { + // This key already exists. Release its handle and continue. + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + } else + break; + + if (iStartNext < 0) break; + iStart = iStartNext + 1; + } + + if (lResult == ERROR_SUCCESS) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_CREATE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 4, lResult ) == ERROR_SUCCESS); + ::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) +{ + assert(pSession); + LONG lResult; + REGSAM samAdditional = 0; + + assert(0); // TODO: Preizkusi ta del kode. + + { + // 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); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_COPY_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue1 ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 4, m_sValue2 ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 5, lResult ) == ERROR_SUCCESS); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + return AtlHresultFromWin32(lResult); + } +} + + +//////////////////////////////////////////////////////////////////////////// +// COpRegKeyDelete +//////////////////////////////////////////////////////////////////////////// + +COpRegKeyDelete::COpRegKeyDelete(HKEY hKeyRoot, LPCWSTR m_hKeyRoot, int iTicks) : COpRegKeySingle(hKeyRoot, m_hKeyRoot, iTicks) +{ +} + + +HRESULT COpRegKeyDelete::Execute(CSession *pSession) +{ + assert(pSession); + LONG lResult; + REGSAM samAdditional = 0; + + assert(0); // TODO: Preizkusi ta del kode. + +#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) { + // Make a backup of the key first. + ATL::CAtlStringW sBackupName; + UINT uiCount = 0; + + for (;;) { + HKEY hKey; + sBackupName.Format(L"%ls (orig %u)", (LPCWSTR)m_sValue, ++uiCount); + lResult = ::RegOpenKeyExW(m_hKeyRoot, sBackupName, 0, KEY_ENUMERATE_SUB_KEYS | samAdditional, &hKey); + if (lResult != ERROR_SUCCESS) break; + verify(::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, TRUE)); + } else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_PROBING_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, sBackupName ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 4, lResult ) == ERROR_SUCCESS); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + return AtlHresultFromWin32(lResult); + } + } + + // Delete the registry key. + lResult = DeleteKeyRecursively(m_hKeyRoot, m_sValue, KEY_ENUMERATE_SUB_KEYS | samAdditional); + if (lResult == ERROR_SUCCESS) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_DELETE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 4, lResult ) == ERROR_SUCCESS); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + return AtlHresultFromWin32(lResult); + } +} + + +LONG COpRegKeyDelete::DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM sam) +{ + HKEY hKey; + LONG lResult; + + // Open the key. + lResult = ::RegOpenKeyEx(hKeyRoot, pszKeyName, 0, sam, &hKey); + if (lResult == ERROR_SUCCESS) { + DWORD dwMaxSubKeyLen; + + // Determine the largest subkey name. + lResult = ::RegQueryInfoKey(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 TCHAR[dwMaxSubKeyLen]; + if (pszSubKeyName) { + DWORD dwIndex; + + // Iterate over all subkeys and delete them. Skip failed. + for (dwIndex = 0; lResult != ERROR_NO_MORE_ITEMS ;) { + lResult = ::RegEnumKeyEx(hKey, dwIndex, pszSubKeyName, &dwMaxSubKeyLen, NULL, NULL, NULL, NULL); + if (lResult == ERROR_SUCCESS) + lResult = DeleteKeyRecursively(hKey, pszSubKeyName, sam); + else + dwIndex++; + } + + delete [] pszSubKeyName; + } else + lResult = ERROR_OUTOFMEMORY; + } + + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + + // 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; +} + + +} // namespace AMSICA