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