diff --git a/AMSICA/include/AMSICA.h b/AMSICA/include/AMSICA.h index 611f020..c8c9151 100644 --- a/AMSICA/include/AMSICA.h +++ b/AMSICA/include/AMSICA.h @@ -5,13 +5,13 @@ // Version //////////////////////////////////////////////////////////////////////////// -#define AMSICA_VERSION 0x01000000 +#define AMSICA_VERSION 0x01000100 #define AMSICA_VERSION_MAJ 1 #define AMSICA_VERSION_MIN 0 -#define AMSICA_VERSION_REV 0 +#define AMSICA_VERSION_REV 1 -#define AMSICA_VERSION_STR "1.0" +#define AMSICA_VERSION_STR "1.0.1" #if !defined(RC_INVOKED) && !defined(MIDL_PASS) @@ -26,26 +26,30 @@ //////////////////////////////////////////////////////////////////// -// Error codes (next unused 2565L) +// Error codes (next unused 2569L) //////////////////////////////////////////////////////////////////// +#define ERROR_INSTALL_DATABASE_OPEN 2550L +#define ERROR_INSTALL_PROPERTY_SET 2553L +#define ERROR_INSTALL_SCRIPT_WRITE 2552L +#define ERROR_INSTALL_SCRIPT_READ 2560L #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_REGKEY_SETVALUE_FAILED 2565L +#define ERROR_INSTALL_REGKEY_DELETEVALUE_FAILED 2567L +#define ERROR_INSTALL_REGKEY_COPYVALUE_FAILED 2568L +#define ERROR_INSTALL_REGKEY_PROBINGVAL_FAILED 2566L #define ERROR_INSTALL_TASK_CREATE_FAILED 2556L #define ERROR_INSTALL_TASK_DELETE_FAILED 2557L #define ERROR_INSTALL_TASK_ENABLE_FAILED 2558L #define ERROR_INSTALL_TASK_COPY_FAILED 2559L // Errors reported by MSITSCA -#define ERROR_INSTALL_SCHEDULED_TASKS_DATABASE_OPEN 2550L #define ERROR_INSTALL_SCHEDULED_TASKS_OPLIST_CREATE 2551L -#define ERROR_INSTALL_SCHEDULED_TASKS_SCRIPT_WRITE 2552L -#define ERROR_INSTALL_SCHEDULED_TASKS_SCRIPT_READ 2560L -#define ERROR_INSTALL_SCHEDULED_TASKS_PROPERTY_SET 2553L namespace AMSICA { @@ -96,7 +100,7 @@ protected: //////////////////////////////////////////////////////////////////////////// -// COpDoubleStringOperation +// COpTypeSrcDstString //////////////////////////////////////////////////////////////////////////// class COpTypeSrcDstString : public COperation @@ -219,11 +223,12 @@ public: class COpRegKeyCopy : public COpRegKeySrcDst { public: - COpRegKeyCopy(HKEY hKey = NULL, LPCWSTR pszKeyNameSrc = L"", LPCWSTR pszKeyNameDst = L"", int iTicks = 0); + COpRegKeyCopy(HKEY hKeyRoot = 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); + static LONG CopyKeyRecursively(HKEY hKeySrc, HKEY hKeyDst, REGSAM samAdditional); }; @@ -234,11 +239,97 @@ private: class COpRegKeyDelete : public COpRegKeySingle { public: - COpRegKeyDelete(HKEY hKey = NULL, LPCWSTR pszKeyName = L"", int iTicks = 0); + COpRegKeyDelete(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", int iTicks = 0); virtual HRESULT Execute(CSession *pSession); private: - static LONG DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM sam); + static LONG DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM samAdditional); +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegValueSingle +//////////////////////////////////////////////////////////////////////////// + +class COpRegValueSingle : public COpRegKeySingle +{ +public: + COpRegValueSingle(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", LPCWSTR pszValueName = L"", int iTicks = 0); + + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegValueSingle &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpRegValueSingle &op); + +protected: + ATL::CAtlStringW m_sValueName; +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegValueSrcDst +//////////////////////////////////////////////////////////////////////////// + +class COpRegValueSrcDst : public COpRegKeySingle +{ +public: + COpRegValueSrcDst(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", LPCWSTR pszValueNameSrc = L"", LPCWSTR pszValueNameDst = L"", int iTicks = 0); + + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegValueSrcDst &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpRegValueSrcDst &op); + +protected: + ATL::CAtlStringW m_sValueName1; + ATL::CAtlStringW m_sValueName2; +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegValueCreate +//////////////////////////////////////////////////////////////////////////// + +class COpRegValueCreate : public COpRegValueSingle +{ +public: + COpRegValueCreate(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", LPCWSTR pszValueName = L"", int iTicks = 0); + COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, DWORD dwData, int iTicks = 0); + COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, LPCVOID lpData, SIZE_T nSize, int iTicks = 0); + COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, LPCWSTR pszData, int iTicks = 0); + COpRegValueCreate(HKEY hKeyRoot, LPCWSTR pszKeyName, LPCWSTR pszValueName, DWORDLONG qwData, int iTicks = 0); + virtual HRESULT Execute(CSession *pSession); + + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegValueCreate &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpRegValueCreate &op); + +protected: + DWORD m_dwType; + ATL::CAtlStringW m_sData; + ATL::CAtlArray m_binData; + DWORD m_dwData; + ATL::CAtlArray m_szData; + DWORDLONG m_qwData; +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegValueCopy +//////////////////////////////////////////////////////////////////////////// + +class COpRegValueCopy : public COpRegValueSrcDst +{ +public: + COpRegValueCopy(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", LPCWSTR pszValueNameSrc = L"", LPCWSTR pszValueNameDst = L"", int iTicks = 0); + virtual HRESULT Execute(CSession *pSession); +}; + + +//////////////////////////////////////////////////////////////////////////// +// COpRegValueDelete +//////////////////////////////////////////////////////////////////////////// + +class COpRegValueDelete : public COpRegValueSingle +{ +public: + COpRegValueDelete(HKEY hKeyRoot = NULL, LPCWSTR pszKeyName = L"", LPCWSTR pszValueName = L"", int iTicks = 0); + virtual HRESULT Execute(CSession *pSession); }; @@ -339,18 +430,24 @@ public: protected: enum OPERATION { - OPERATION_ENABLE_ROLLBACK = 1, - OPERATION_DELETE_FILE, - OPERATION_MOVE_FILE, - OPERATION_CREATE_TASK, - OPERATION_DELETE_TASK, - OPERATION_ENABLE_TASK, - OPERATION_COPY_TASK, - OPERATION_SUBLIST + OP_ROLLBACK_ENABLE = 1, + OP_FILE_DELETE, + OP_FILE_MOVE, + OP_REG_KEY_CREATE, + OP_REG_KEY_COPY, + OP_REG_KEY_DELETE, + OP_REG_VALUE_CREATE, + OP_REG_VALUE_COPY, + OP_REG_VALUE_DELETE, + OP_TASK_CREATE, + OP_TASK_DELETE, + OP_TASK_ENABLE, + OP_TASK_COPY, + OP_SUBLIST }; protected: - template inline static HRESULT Save(ATL::CAtlFile &f, const COperation *p); + template inline static HRESULT Save(ATL::CAtlFile &f, const COperation *p); template inline HRESULT LoadAndAddTail(ATL::CAtlFile &f); }; @@ -653,13 +750,81 @@ namespace AMSICA { inline HRESULT operator <<(ATL::CAtlFile &f, int i) { - return f.Write(&i, sizeof(int)); + HRESULT hr; + DWORD dwWritten; + + hr = f.Write(&i, sizeof(int), &dwWritten); + return SUCCEEDED(hr) ? dwWritten == sizeof(int) ? hr : E_FAIL : hr; } inline HRESULT operator >>(ATL::CAtlFile &f, int &i) { - return f.Read(&i, sizeof(int)); + HRESULT hr; + DWORD dwRead; + + hr = f.Read(&i, sizeof(int), dwRead); + return SUCCEEDED(hr) ? dwRead == sizeof(int) ? hr : E_FAIL : hr; +} + + +inline HRESULT operator <<(ATL::CAtlFile &f, DWORDLONG i) +{ + HRESULT hr; + DWORD dwWritten; + + hr = f.Write(&i, sizeof(DWORDLONG), &dwWritten); + return SUCCEEDED(hr) ? dwWritten == sizeof(DWORDLONG) ? hr : E_FAIL : hr; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, DWORDLONG &i) +{ + HRESULT hr; + DWORD dwRead; + + hr = f.Read(&i, sizeof(DWORDLONG), dwRead); + return SUCCEEDED(hr) ? dwRead == sizeof(DWORDLONG) ? hr : E_FAIL : hr; +} + + +template +inline HRESULT operator <<(ATL::CAtlFile &f, const ATL::CAtlArray &a) +{ + assert(a.GetCount() <= INT_MAX); + + HRESULT hr; + DWORD dwCount = (DWORD)a.GetCount(), dwWritten; + + // Write element count. + hr = f.Write(&dwCount, sizeof(DWORD), &dwWritten); + if (FAILED(hr)) return hr; + if (dwWritten < sizeof(DWORD)) return E_FAIL; + + // Write data. + hr = f.Write(a.GetData(), sizeof(E) * dwCount, &dwWritten); + return SUCCEEDED(hr) ? dwWritten == sizeof(E) * dwCount ? hr : E_FAIL : hr; +} + + +template +inline HRESULT operator >>(ATL::CAtlFile &f, ATL::CAtlArray &a) +{ + HRESULT hr; + DWORD dwCount, dwRead; + + // Read element count as 32-bit integer. + hr = f.Read(&dwCount, sizeof(DWORD), dwRead); + if (FAILED(hr)) return hr; + if (dwRead < sizeof(DWORD)) return E_FAIL; + + // Allocate the buffer. + if (!a.SetCount(dwCount)) return E_OUTOFMEMORY; + + // Read data. + hr = f.Read(a.GetData(), sizeof(E) * dwCount, dwRead); + if (SUCCEEDED(hr)) a.SetCount(dwRead / sizeof(E)); + return hr; } @@ -667,13 +832,16 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const ATL::CAtlStringA &str) { HRESULT hr; int iLength = str.GetLength(); + DWORD dwWritten; // Write string length (in characters) as 32-bit integer. - hr = f.Write(&iLength, sizeof(int)); + hr = f.Write(&iLength, sizeof(int), &dwWritten); if (FAILED(hr)) return hr; + if (dwWritten < sizeof(int)) return E_FAIL; // Write string data (without terminator). - return f.Write((LPCSTR)str, sizeof(CHAR) * iLength); + hr = f.Write((LPCSTR)str, sizeof(CHAR) * iLength, &dwWritten); + return SUCCEEDED(hr) ? dwWritten == sizeof(CHAR) * iLength ? hr : E_FAIL : hr; } @@ -682,18 +850,20 @@ inline HRESULT operator >>(ATL::CAtlFile &f, ATL::CAtlStringA &str) HRESULT hr; int iLength; LPSTR buf; + DWORD dwRead; // Read string length (in characters) as 32-bit integer. - hr = f.Read(&iLength, sizeof(int)); + hr = f.Read(&iLength, sizeof(int), dwRead); if (FAILED(hr)) return hr; + if (dwRead < sizeof(int)) return E_FAIL; // Allocate the buffer. buf = str.GetBuffer(iLength); if (!buf) return E_OUTOFMEMORY; // Read string data (without terminator). - hr = f.Read(buf, sizeof(CHAR) * iLength); - str.ReleaseBuffer(SUCCEEDED(hr) ? iLength : 0); + hr = f.Read(buf, sizeof(CHAR) * iLength, dwRead); + str.ReleaseBuffer(SUCCEEDED(hr) ? dwRead / sizeof(CHAR) : 0); return hr; } @@ -702,13 +872,16 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const ATL::CAtlStringW &str) { HRESULT hr; int iLength = str.GetLength(); + DWORD dwWritten; // Write string length (in characters) as 32-bit integer. - hr = f.Write(&iLength, sizeof(int)); + hr = f.Write(&iLength, sizeof(int), &dwWritten); if (FAILED(hr)) return hr; + if (dwWritten < sizeof(int)) return E_FAIL; // Write string data (without terminator). - return f.Write((LPCWSTR)str, sizeof(WCHAR) * iLength); + hr = f.Write((LPCWSTR)str, sizeof(WCHAR) * iLength, &dwWritten); + return SUCCEEDED(hr) ? dwWritten == sizeof(WCHAR) * iLength ? hr : E_FAIL : hr; } @@ -717,31 +890,41 @@ inline HRESULT operator >>(ATL::CAtlFile &f, ATL::CAtlStringW &str) HRESULT hr; int iLength; LPWSTR buf; + DWORD dwRead; // Read string length (in characters) as 32-bit integer. - hr = f.Read(&iLength, sizeof(int)); + hr = f.Read(&iLength, sizeof(int), dwRead); if (FAILED(hr)) return hr; + if (dwRead < sizeof(int)) return E_FAIL; // Allocate the buffer. buf = str.GetBuffer(iLength); if (!buf) return E_OUTOFMEMORY; // Read string data (without terminator). - hr = f.Read(buf, sizeof(WCHAR) * iLength); - str.ReleaseBuffer(SUCCEEDED(hr) ? iLength : 0); + hr = f.Read(buf, sizeof(WCHAR) * iLength, dwRead); + str.ReleaseBuffer(SUCCEEDED(hr) ? dwRead / sizeof(WCHAR) : 0); return hr; } inline HRESULT operator <<(ATL::CAtlFile &f, const TASK_TRIGGER &ttData) { - return f.Write(&ttData, sizeof(TASK_TRIGGER)); + HRESULT hr; + DWORD dwWritten; + + hr = f.Write(&ttData, sizeof(TASK_TRIGGER), &dwWritten); + return SUCCEEDED(hr) ? dwWritten == sizeof(TASK_TRIGGER) ? hr : E_FAIL : hr; } inline HRESULT operator >>(ATL::CAtlFile &f, TASK_TRIGGER &ttData) { - return f.Read(&ttData, sizeof(TASK_TRIGGER)); + HRESULT hr; + DWORD dwRead; + + hr = f.Read(&ttData, sizeof(TASK_TRIGGER), dwRead); + return SUCCEEDED(hr) ? dwRead == sizeof(TASK_TRIGGER) ? hr : E_FAIL : hr; } @@ -761,10 +944,10 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeSingleString &op) { HRESULT hr; - hr = f << (const COperation &)op; - if (FAILED(hr)) return hr; + hr = f << (const COperation &)op; if (FAILED(hr)) return hr; + hr = f << op.m_sValue; if (FAILED(hr)) return hr; - return f << op.m_sValue; + return S_OK; } @@ -772,10 +955,10 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeSingleString &op) { HRESULT hr; - hr = f >> (COperation &)op; - if (FAILED(hr)) return hr; + hr = f >> (COperation &)op; if (FAILED(hr)) return hr; + hr = f >> op.m_sValue; if (FAILED(hr)) return hr; - return f >> op.m_sValue; + return S_OK; } @@ -783,13 +966,11 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeSrcDstString &op) { HRESULT hr; - hr = f << (const COperation &)op; - if (FAILED(hr)) return hr; + hr = f << (const COperation &)op; if (FAILED(hr)) return hr; + hr = f << op.m_sValue1; if (FAILED(hr)) return hr; + hr = f << op.m_sValue2; if (FAILED(hr)) return hr; - hr = f << op.m_sValue1; - if (FAILED(hr)) return hr; - - return f << op.m_sValue2; + return S_OK; } @@ -797,13 +978,11 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeSrcDstString &op) { HRESULT hr; - hr = f >> (COperation &)op; - if (FAILED(hr)) return hr; + hr = f >> (COperation &)op; if (FAILED(hr)) return hr; + hr = f >> op.m_sValue1; if (FAILED(hr)) return hr; + hr = f >> op.m_sValue2; if (FAILED(hr)) return hr; - hr = f >> op.m_sValue1; - if (FAILED(hr)) return hr; - - return f >> op.m_sValue2; + return S_OK; } @@ -811,10 +990,10 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpTypeBoolean &op) { HRESULT hr; - hr = f << (const COperation &)op; - if (FAILED(hr)) return hr; + hr = f << (const COperation &)op; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_bValue); if (FAILED(hr)) return hr; - return f << (int)op.m_bValue; + return S_OK; } @@ -823,18 +1002,13 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpTypeBoolean &op) HRESULT hr; int iValue; - hr = f >> (COperation &)op; - if (FAILED(hr)) return hr; - - hr = f >> iValue; - if (FAILED(hr)) return hr; - op.m_bValue = iValue ? TRUE : FALSE; + hr = f >> (COperation &)op; if (FAILED(hr)) return hr; + hr = f >> iValue; if (FAILED(hr)) return hr; op.m_bValue = iValue ? TRUE : FALSE; return S_OK; } - inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegKeySingle &op) { HRESULT hr; @@ -881,6 +1055,96 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpRegKeySrcDst &op) } +inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegValueSingle &op) +{ + HRESULT hr; + + hr = f << (const COpRegKeySingle &)op; if (FAILED(hr)) return hr; + hr = f << op.m_sValueName; if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, COpRegValueSingle &op) +{ + HRESULT hr; + + hr = f >> (COpRegKeySingle &)op; if (FAILED(hr)) return hr; + hr = f >> op.m_sValueName; if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegValueSrcDst &op) +{ + HRESULT hr; + + hr = f << (const COpRegKeySingle &)op; if (FAILED(hr)) return hr; + hr = f << op.m_sValueName1; if (FAILED(hr)) return hr; + hr = f << op.m_sValueName2; if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, COpRegValueSrcDst &op) +{ + HRESULT hr; + + hr = f >> (COpRegKeySingle &)op; if (FAILED(hr)) return hr; + hr = f >> op.m_sValueName1; if (FAILED(hr)) return hr; + hr = f >> op.m_sValueName2; if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator <<(ATL::CAtlFile &f, const COpRegValueCreate &op) +{ + HRESULT hr; + + hr = f << (const COpRegValueSingle &)op; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_dwType); if (FAILED(hr)) return hr; + switch (op.m_dwType) { + case REG_SZ: + case REG_EXPAND_SZ: + case REG_LINK: hr = f << op.m_sData; if (FAILED(hr)) return hr; break; + case REG_BINARY: hr = f << op.m_binData; if (FAILED(hr)) return hr; break; + case REG_DWORD_LITTLE_ENDIAN: + case REG_DWORD_BIG_ENDIAN: hr = f << (int)(op.m_dwData); if (FAILED(hr)) return hr; break; + case REG_MULTI_SZ: hr = f << op.m_szData; if (FAILED(hr)) return hr; break; + case REG_QWORD_LITTLE_ENDIAN: hr = f << op.m_qwData; if (FAILED(hr)) return hr; break; + default: assert(0); return E_UNEXPECTED; + } + + return S_OK; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, COpRegValueCreate &op) +{ + HRESULT hr; + + hr = f >> (COpRegValueSingle &)op; if (FAILED(hr)) return hr; + hr = f >> (int&)(op.m_dwType); if (FAILED(hr)) return hr; + switch (op.m_dwType) { + case REG_SZ: + case REG_EXPAND_SZ: + case REG_LINK: hr = f >> op.m_sData; if (FAILED(hr)) return hr; break; + case REG_BINARY: hr = f >> op.m_binData; if (FAILED(hr)) return hr; break; + case REG_DWORD_LITTLE_ENDIAN: + case REG_DWORD_BIG_ENDIAN: hr = f >> (int&)(op.m_dwData); if (FAILED(hr)) return hr; break; + case REG_MULTI_SZ: hr = f >> op.m_szData; if (FAILED(hr)) return hr; break; + case REG_QWORD_LITTLE_ENDIAN: hr = f >> op.m_qwData; if (FAILED(hr)) return hr; break; + default: assert(0); return E_UNEXPECTED; + } + + return S_OK; +} + + inline HRESULT operator <<(ATL::CAtlFile &f, const COpTaskCreate &op) { HRESULT hr; @@ -892,13 +1156,13 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpTaskCreate &op) hr = f << op.m_sWorkingDirectory; if (FAILED(hr)) return hr; hr = f << op.m_sAuthor; if (FAILED(hr)) return hr; hr = f << op.m_sComment; if (FAILED(hr)) return hr; - hr = f << (int)op.m_dwFlags; if (FAILED(hr)) return hr; - hr = f << (int)op.m_dwPriority; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_dwFlags); if (FAILED(hr)) return hr; + hr = f << (int)(op.m_dwPriority); if (FAILED(hr)) return hr; hr = f << op.m_sAccountName; if (FAILED(hr)) return hr; hr = f << op.m_sPassword; if (FAILED(hr)) return hr; hr = f << (int)MAKELONG(op.m_wDeadlineMinutes, op.m_wIdleMinutes); if (FAILED(hr)) return hr; - hr = f << (int)op.m_dwMaxRuntimeMS; if (FAILED(hr)) return hr; - hr = f << (int)op.m_lTriggers.GetCount(); if (FAILED(hr)) return hr; + hr = f << (int)(op.m_dwMaxRuntimeMS); if (FAILED(hr)) return hr; + hr = f << (int)(op.m_lTriggers.GetCount()); if (FAILED(hr)) return hr; for (pos = op.m_lTriggers.GetHeadPosition(); pos;) { hr = f << op.m_lTriggers.GetNext(pos); if (FAILED(hr)) return hr; @@ -941,10 +1205,10 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpTaskEnable &op) { HRESULT hr; - hr = f << (const COpTypeSingleString&)op; - if (FAILED(hr)) return hr; + hr = f << (const COpTypeSingleString&)op; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_bEnable); if (FAILED(hr)) return hr; - return f << (int)op.m_bEnable; + return S_OK; } @@ -953,12 +1217,8 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpTaskEnable &op) HRESULT hr; int iTemp; - hr = f >> (COpTypeSingleString&)op; - if (FAILED(hr)) return hr; - - hr = f >> iTemp; - if (FAILED(hr)) return hr; - op.m_bEnable = iTemp ? TRUE : FALSE; + hr = f >> (COpTypeSingleString&)op; if (FAILED(hr)) return hr; + hr = f >> iTemp; if (FAILED(hr)) return hr; op.m_bEnable = iTemp ? TRUE : FALSE; return S_OK; } @@ -972,27 +1232,39 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpList &list) hr = f << (const COperation &)list; if (FAILED(hr)) return hr; - hr = f << (int)list.GetCount(); + hr = f << (int)(list.GetCount()); if (FAILED(hr)) return hr; for (pos = list.GetHeadPosition(); pos;) { const COperation *pOp = list.GetNext(pos); if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); + else if (dynamic_cast(pOp)) + hr = list.Save(f, pOp); + else if (dynamic_cast(pOp)) + hr = list.Save(f, pOp); + else if (dynamic_cast(pOp)) + hr = list.Save(f, pOp); + else if (dynamic_cast(pOp)) + hr = list.Save(f, pOp); + else if (dynamic_cast(pOp)) + hr = list.Save(f, pOp); + else if (dynamic_cast(pOp)) + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); + hr = list.Save(f, pOp); else { // Unsupported type of operation. assert(0); @@ -1009,43 +1281,61 @@ inline HRESULT operator <<(ATL::CAtlFile &f, const COpList &list) inline HRESULT operator >>(ATL::CAtlFile &f, COpList &list) { HRESULT hr; - DWORD dwCount; + int iCount; hr = f >> (COperation &)list; if (FAILED(hr)) return hr; - hr = f >> (int&)dwCount; + hr = f >> iCount; if (FAILED(hr)) return hr; - while (dwCount--) { + while (iCount--) { int iTemp; hr = f >> iTemp; if (FAILED(hr)) return hr; switch ((COpList::OPERATION)iTemp) { - case COpList::OPERATION_ENABLE_ROLLBACK: + case COpList::OP_ROLLBACK_ENABLE: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_DELETE_FILE: + case COpList::OP_FILE_DELETE: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_MOVE_FILE: + case COpList::OP_FILE_MOVE: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_CREATE_TASK: + case COpList::OP_REG_KEY_CREATE: + hr = list.LoadAndAddTail(f); + break; + case COpList::OP_REG_KEY_COPY: + hr = list.LoadAndAddTail(f); + break; + case COpList::OP_REG_KEY_DELETE: + hr = list.LoadAndAddTail(f); + break; + case COpList::OP_REG_VALUE_CREATE: + hr = list.LoadAndAddTail(f); + break; + case COpList::OP_REG_VALUE_COPY: + hr = list.LoadAndAddTail(f); + break; + case COpList::OP_REG_VALUE_DELETE: + hr = list.LoadAndAddTail(f); + break; + case COpList::OP_TASK_CREATE: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_DELETE_TASK: + case COpList::OP_TASK_DELETE: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_ENABLE_TASK: + case COpList::OP_TASK_ENABLE: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_COPY_TASK: + case COpList::OP_TASK_COPY: hr = list.LoadAndAddTail(f); break; - case COpList::OPERATION_SUBLIST: + case COpList::OP_SUBLIST: hr = list.LoadAndAddTail(f); break; default: @@ -1103,7 +1393,7 @@ inline BOOL IsWow64Process() // Inline methods //////////////////////////////////////////////////////////////////////////// -template inline static HRESULT COpList::Save(ATL::CAtlFile &f, const COperation *p) +template inline static HRESULT COpList::Save(ATL::CAtlFile &f, const COperation *p) { assert(p); HRESULT hr; diff --git a/AMSICA/msm/Makefile b/AMSICA/msm/Makefile index 273750a..63dfb46 100644 --- a/AMSICA/msm/Makefile +++ b/AMSICA/msm/Makefile @@ -31,6 +31,10 @@ Error Error Error Message i2 L0 1250 Error Error +2550 Pri odpiranju namestitvenega paketa je prilo do napake. Obrnite se na svojo tehnino slubo. +2552 Pri pisanju v datoteko seznama opravil [2] je prilo do napake [3]. Obrnite se na svojo tehnino slubo. +2560 Pri branju iz datoteke seznama opravil [2] je prilo do napake [3]. Obrnite se na svojo tehnino slubo. +2553 Pri nastavljanju parametra [2] je prilo do napake [3]. Obrnite se na svojo tehnino slubo. 2554 Pri brisanju datoteke [2] je prilo do napake [3]. Obrnite se na svojo tehnino slubo. 2555 Pri premikanju datoteke [2] v [3] je prilo do napake [4]. Obrnite se na svojo tehnino slubo. 2556 Pri ustvarjanju razporejenega opravila [2] je prilo do napake [3]. Obrnite se na svojo tehnino slubo. diff --git a/AMSICA/res/en_GB.po b/AMSICA/res/en_GB.po index d5b6544..98f1172 100644 --- a/AMSICA/res/en_GB.po +++ b/AMSICA/res/en_GB.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: MSITSCA\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-26 11:07+0100\n" +"POT-Creation-Date: 2013-06-07 21:16+0100\n" "PO-Revision-Date: \n" "Last-Translator: Simon Rozman \n" "Language-Team: Amebis, d. o. o., Kamnik \n" @@ -19,20 +19,25 @@ msgstr "" # 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 -#: ..\msm/Sl.ReleaseU.Win32.Error-2.idtx:3 msgid "1250" msgstr "1252" -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:4 ..\msm/Sl.DebugU.x64.Error-2.idtx:4 -#: ..\msm/Sl.ReleaseU.Win32.Error-2.idtx:4 +#: ..\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:7 ..\msm/Sl.DebugU.x64.Error-2.idtx:7 -#: ..\msm/Sl.ReleaseU.Win32.Error-2.idtx:7 +#: ..\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." @@ -40,8 +45,7 @@ msgstr "" "Error [3] deleting \"[2]\" scheduled task. Please, contact your support " "personnel." -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:9 ..\msm/Sl.DebugU.x64.Error-2.idtx:9 -#: ..\msm/Sl.ReleaseU.Win32.Error-2.idtx:9 +#: ..\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." @@ -49,8 +53,14 @@ msgstr "" "Error [4] copying \"[2]\" scheduled task to \"[3]\". Please, contact your " "support personnel." -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:8 ..\msm/Sl.DebugU.x64.Error-2.idtx:8 -#: ..\msm/Sl.ReleaseU.Win32.Error-2.idtx:8 +#: ..\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." @@ -58,8 +68,22 @@ 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 -#: ..\msm/Sl.ReleaseU.Win32.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." @@ -67,8 +91,7 @@ msgstr "" "Error [4] moving \"[2]\" file to \"[3]\". Please, contact your support " "personnel." -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:6 ..\msm/Sl.DebugU.x64.Error-2.idtx:6 -#: ..\msm/Sl.ReleaseU.Win32.Error-2.idtx:6 +#: ..\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." diff --git a/AMSICA/src/AMSICA.cpp b/AMSICA/src/AMSICA.cpp index 64665a2..ba2abd2 100644 --- a/AMSICA/src/AMSICA.cpp +++ b/AMSICA/src/AMSICA.cpp @@ -1,5 +1,7 @@ #include "StdAfx.h" +#pragma comment(lib, "msi.lib") + namespace AMSICA { @@ -25,7 +27,7 @@ COpTypeSingleString::COpTypeSingleString(LPCWSTR pszValue, int iTicks) : //////////////////////////////////////////////////////////////////////////// -// COpDoubleStringOperation +// COpTypeSrcDstString //////////////////////////////////////////////////////////////////////////// COpTypeSrcDstString::COpTypeSrcDstString(LPCWSTR pszValue1, LPCWSTR pszValue2, int iTicks) : diff --git a/AMSICA/src/AMSICATSOp.cpp b/AMSICA/src/AMSICATSOp.cpp index 3b816ce..9cecbe9 100644 --- a/AMSICA/src/AMSICATSOp.cpp +++ b/AMSICA/src/AMSICATSOp.cpp @@ -1,5 +1,6 @@ #include "StdAfx.h" +#pragma comment(lib, "mstask.lib") #pragma comment(lib, "taskschd.lib") diff --git a/AMSICA/src/MSICARegOp.cpp b/AMSICA/src/MSICARegOp.cpp index 90020b5..c98612c 100644 --- a/AMSICA/src/MSICARegOp.cpp +++ b/AMSICA/src/MSICARegOp.cpp @@ -43,8 +43,6 @@ HRESULT COpRegKeyCreate::Execute(CSession *pSession) 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. @@ -114,8 +112,6 @@ HRESULT COpRegKeyCopy::Execute(CSession *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. @@ -154,11 +150,143 @@ HRESULT COpRegKeyCopy::Execute(CSession *pSession) } +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 hKeyRoot, LPCWSTR m_hKeyRoot, int iTicks) : COpRegKeySingle(hKeyRoot, m_hKeyRoot, iTicks) +COpRegKeyDelete::COpRegKeyDelete(HKEY hKey, LPCWSTR pszKeyName, int iTicks) : COpRegKeySingle(hKey, pszKeyName, iTicks) { } @@ -167,10 +295,9 @@ HRESULT COpRegKeyDelete::Execute(CSession *pSession) { assert(pSession); LONG lResult; + HKEY hKey; 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. @@ -178,43 +305,54 @@ HRESULT COpRegKeyDelete::Execute(CSession *pSession) } #endif - if (pSession->m_bRollbackEnabled) { - // Make a backup of the key first. - ATL::CAtlStringW sBackupName; - UINT uiCount = 0; + // Probe to see if the key exists. + lResult = ::RegOpenKeyExW(m_hKeyRoot, m_sValue, 0, DELETE | samAdditional, &hKey); + if (lResult == ERROR_SUCCESS) { + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); - 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 (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; + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + } + 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); + 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); + } } - 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, samAdditional); } - // Delete the registry key. - lResult = DeleteKeyRecursively(m_hKeyRoot, m_sValue, KEY_ENUMERATE_SUB_KEYS | samAdditional); - if (lResult == ERROR_SUCCESS) + if (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND) return S_OK; else { PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); @@ -228,33 +366,39 @@ HRESULT COpRegKeyDelete::Execute(CSession *pSession) } -LONG COpRegKeyDelete::DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM sam) +LONG COpRegKeyDelete::DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, REGSAM samAdditional) { HKEY hKey; LONG lResult; // Open the key. - lResult = ::RegOpenKeyEx(hKeyRoot, pszKeyName, 0, sam, &hKey); + lResult = ::RegOpenKeyExW(hKeyRoot, pszKeyName, 0, DELETE | KEY_READ | samAdditional, &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); + 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 TCHAR[dwMaxSubKeyLen]; + pszSubKeyName = new WCHAR[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 + 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++; } @@ -266,7 +410,7 @@ LONG COpRegKeyDelete::DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, RE verify(::RegCloseKey(hKey) == ERROR_SUCCESS); // Finally try to delete the key. - lResult = ::RegDeleteKeyW(hKeyRoot, pszKeyName); + lResult = ::RegDeleteKeyExW(hKeyRoot, pszKeyName, samAdditional, 0); } else if (lResult == ERROR_FILE_NOT_FOUND) { // The key doesn't exist. Not really an error in this case. lResult = ERROR_SUCCESS; @@ -276,4 +420,314 @@ LONG COpRegKeyDelete::DeleteKeyRecursively(HKEY hKeyRoot, LPCWSTR pszKeyName, RE } +//////////////////////////////////////////////////////////////////////////// +// 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) +{ + assert(lpData || !nSize); + verify(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) +{ + assert(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: + assert(0); + lResult = ERROR_UNSUPPORTED_TYPE; + } + + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + } + + if (lResult == ERROR_SUCCESS) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(5); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_SETVALUE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 4, m_sValueName ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 5, lResult ) == ERROR_SUCCESS); + ::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) +{ + assert(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]; + assert(lpData); + // 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; + } + + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + } + + if (lResult == ERROR_SUCCESS) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(6); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_COPYVALUE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 4, m_sValueName1 ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 5, m_sValueName2 ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 6, lResult ) == ERROR_SUCCESS); + ::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) +{ + assert(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)) { + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + 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); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_PROBINGVAL_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, sBackupName ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 4, lResult ) == ERROR_SUCCESS); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + return AtlHresultFromWin32(lResult); + } + } + + // Delete the registry value. + lResult = ::RegDeleteValueW(hKey, m_sValueName); + } + + verify(::RegCloseKey(hKey) == ERROR_SUCCESS); + } + + if (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(5); + verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_REGKEY_DELETEVALUE_FAILED) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 2, (UINT)m_hKeyRoot & 0x7fffffff ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue ) == ERROR_SUCCESS); + verify(::MsiRecordSetStringW(hRecordProg, 4, m_sValueName ) == ERROR_SUCCESS); + verify(::MsiRecordSetInteger(hRecordProg, 5, lResult ) == ERROR_SUCCESS); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + return AtlHresultFromWin32(lResult); + } +} + } // namespace AMSICA