diff options
author | Stef Walter <stef@thewalter.net> | 2003-09-17 19:07:23 +0000 |
---|---|---|
committer | Stef Walter <stef@thewalter.net> | 2003-09-17 19:07:23 +0000 |
commit | 3f95d417d9e623ac0c74df8ef11d7a01846392dd (patch) | |
tree | 45ec73f2dc07eafd7f41a6f62a8cdfbaa279469f /Shutdown/LogDlg.cpp |
Diffstat (limited to 'Shutdown/LogDlg.cpp')
-rw-r--r-- | Shutdown/LogDlg.cpp | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/Shutdown/LogDlg.cpp b/Shutdown/LogDlg.cpp new file mode 100644 index 0000000..3d94bc9 --- /dev/null +++ b/Shutdown/LogDlg.cpp @@ -0,0 +1,502 @@ +// LogDlg.cpp : Implementation of CShutdownApp and DLL registration. + +#include "stdafx.h" +#include "LogDlg.h" + +#include <algorithm> +using std::replace; + +_COM_SMARTPTR_TYPEDEF(INightSecErrorFix, __uuidof(INightSecErrorFix)); + +#include <appmisc.h> +#include <shlobj.h> + +#define IMAGE_OKAY 0 +#define IMAGE_ERROR 1 + +///////////////////////////////////////////////////////////////////////////// +// +LRESULT CLogDlg::OnHide(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + // We use this event to keep the program open + // when the user is looking at the log + if(m_hEvent) + SetEvent(m_hEvent); + + ShowWindow(SW_HIDE); + return 0; +} + +LRESULT CLogDlg::OnSave(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + // I think this is good enough. ie: saving on the desktop. + if(IDYES == MessageBox(_T("The log will be saved on your desktop. Continue?"), _T("Save Log"), MB_YESNO | MB_ICONQUESTION)) + SaveLog(); + + return 0; +} + +LRESULT CLogDlg::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + OnHide(0, 0, NULL, bHandled); + return 0; +} + +/*LRESULT CLogDlg::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + return 0; +} +*/ +////////////////////////////////////////////////////////////////// +// InitDialog (what more can I say) + +LRESULT CLogDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + m_hIcon = ::LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ERR)); + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // Create the small icon image list. + m_ImageListSmall.Create(IDB_ERRORS, + 16, + 0, // list won't grow + RGB(255, 0, 255)); + + // Set Mask color for Image Lists + m_ImageListSmall.SetBkColor(CLR_NONE); + + m_ctlErrors = GetDlgItem(IDC_ERROR_LOG); + + // Associate the image lists with the list view control. + m_ctlErrors.SetImageList(m_ImageListSmall, LVSIL_SMALL); + + // This sets the sizing of the dialog + SetMin(IDC_MINSIZE); + SetControlSizing(ID_SAVE, SD_HORZ | SD_MOVING); + SetControlSizing(ID_HIDE, SD_HORZ | SD_MOVING); + SetControlSizing(IDC_ERROR_LOG, SD_HORZ | SD_VERT | SD_SIZING); + + // We need at least one bogus column since we're using + // report view + LV_COLUMN lvC; // list view column structure + + // Now initialize the columns you will need. + // Initialize the LV_COLUMN structure. + // The mask specifies that the fmt, width, pszText, and subitem members + // of the structure are valid. + lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvC.fmt = LVCFMT_LEFT; // left-align column + lvC.cx = 200; // width of column in pixels + lvC.iSubItem = 0; + lvC.pszText = _T("Errors"); + + if (m_ctlErrors.InsertColumn(0, &lvC) == -1) + return true; + + // Make sure the column is the width of control + RECT rect; + m_ctlErrors.GetClientRect(&rect); + m_ctlErrors.SetColumnWidth(0, rect.right); + + // Move Window to previous position + if(!LoadPosition(_Module.m_settings)) + // If fails then Center it on the desktop + CenterWindow(GetDesktopWindow()); + + // This event gets set when we're hidden + m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +LRESULT CLogDlg::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + // Clear All Items (which also releases the COM Objects) + while(m_ctlErrors.GetItemCount()) + RemoveItem(0); + + // Just in case set the event + if(m_hEvent) + SetEvent(m_hEvent); + + // Put window position in registry for next time + SavePosition(_Module.m_settings); + + return 0; +} + +////////////////////////////////////////////////////////////////// +// Gives the item a tick or cross image depending on bState + +bool CLogDlg::AddItem(INightSecError* pError) +{ + USES_CONVERSION; + + if(!pError) + return false; + + // Get the Description of the Error + BSTR bsTemp; + HRESULT hr = pError->get_Description(&bsTemp); + + if(FAILED(hr)) + return false; + + // Clean up any new lines + replace(bsTemp, bsTemp + SysStringLen(bsTemp), L'\n', L' '); + replace(bsTemp, bsTemp + SysStringLen(bsTemp), L'\r', L' '); + + // Make sure object stays around + pError->AddRef(); + + // Create or Show the Log Window + ShowLog(); + + // Setup Structures + LV_ITEM lv; + lv.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM; + lv.iSubItem = 0; + lv.iItem = m_ctlErrors.GetItemCount(); + lv.iImage = 1; + lv.lParam = (LPARAM)pError; + lv.pszText = OLE2T(bsTemp); + + // Set right image for item + return m_ctlErrors.InsertItem(&lv) ? true : false; +} + +void CLogDlg::ShowLog() +{ + // If not created then Create + if(!IsWindow()) + Create(m_hWndParent, NULL); + + // Make sure it's Visible + if(!IsWindowVisible()) + ShowWindow(SW_SHOW); + + // Make sure event is not signalled so we don't just close by self + ResetEvent(m_hEvent); +} + +void CLogDlg::WaitLog() +{ + // Prompt the user + UINT nRet = MessageBoxTimeout(g_site.m_log, _T("There were errors during Secure Shutdown. \n\nWould you like to pause a moment before continuing?"), _T("Secure Shutdown"), MB_YESNO | MB_ICONQUESTION, 10000, 5000); + + if(nRet == IDYES) + { + // Display the Log Window + ShowLog(); + + // Wait for the Event + if(m_hEvent) + WaitForAndIdle(1, &m_hEvent, INFINITE); + } + + // If we time out then save the log on the desktop + else if(nRet == IDTIMEOUT) + if(!_Module.m_settings.GetInt(NO_LOG_KEY, false)) + SaveLog(); +} + +HRESULT CLogDlg::SaveLog(/*const string& sFile*/) +{ + string sFile; + LPITEMIDLIST pidl; + HRESULT hr; + + // Get Desktop PIDL + hr = SHGetSpecialFolderLocation(*this, CSIDL_DESKTOPDIRECTORY, &pidl); + + if(FAILED(hr)) + return 0; + + // Get the Folder from That + if(!SHGetPathFromIDList(pidl, sFile.get_buffer(MAX_PATH))) + return 0; + + sFile.release_buffer(); + + // This is the file name + // LIMITATION: Can't be changed + sFile += _T("\\Secure Shutdown Log.txt"); + + // Open the File + HANDLE hFile = NULL; + if((hFile = CreateFile(sFile, GENERIC_WRITE, FILE_SHARE_READ, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(::GetLastError()); + + int nPos = -1; + DWORD dwWritten; + + // Always use ANSI here + // LIMITATION: Only errors up to 1K in length + char* szText = new char[1024]; + + // Write Header + char* szTemp = "SECURE SHUTDOWN ERROR LOG\r\n\r\n"; + WriteFile(hFile, szTemp, strlen(szTemp), &dwWritten, NULL); + + LVITEMA lvi; + memset(&lvi, 0, sizeof(LVITEMA)); + + while((nPos = m_ctlErrors.GetNextItem(nPos, 0)) != -1) + { + // We need all this crazy code here to make sure + // We get ANSI text in UNICODE Builds. + lvi.mask = LVIF_TEXT | LVIF_IMAGE; + lvi.iItem = nPos; + lvi.iSubItem = 0; + lvi.cchTextMax = 1024; + lvi.pszText = szText; + lvi.iImage = 0; + + ::SendMessageA(m_ctlErrors, LVM_GETITEMA, 0, (LPARAM)&lvi); + + // Only write errors (No Fixed) + if(lvi.iImage != IMAGE_OKAY) + { + // Write it to the file + WriteFile(hFile, szText, strlen(szText), &dwWritten, NULL); + WriteFile(hFile, "\r\n", 2, &dwWritten, NULL); + } + } + + // Close the File + CloseHandle(hFile); + + return S_OK; +} + +bool CLogDlg::HasErrors() +{ + if(!IsWindow()) + return false; + + // If we're created then we've got errors + int nPos = -1; + LV_ITEM lv; + while((nPos = m_ctlErrors.GetNextItem(nPos, LVNI_ALL)) != -1) + { + lv.mask = LVIF_IMAGE; + lv.iItem = nPos; + lv.iSubItem = 0; + m_ctlErrors.GetItem(&lv); + + if(lv.iImage == IMAGE_ERROR) + return true; + } + + return false; +} + +LRESULT CLogDlg::OnListRClick(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) +{ + // First of all get the mouse incase we move (unlikely) + POINT ptMouse; + ::GetCursorPos(&ptMouse); + + LVHITTESTINFO lvHit; + lvHit.pt = ptMouse; + lvHit.flags = LVHT_ONITEM; + + m_ctlErrors.ScreenToClient(&lvHit.pt); + int nIndex = m_ctlErrors.HitTest(&lvHit); + + // If we didn't click on an item then... + if(nIndex == -1) + { + // ...Deselect All + for(int nCnt = 0; nCnt < m_ctlErrors.GetItemCount(); nCnt ++) + // Set right state for item + ListView_SetItemState(m_ctlErrors, nCnt, 0, (UINT)-1); + + return 0; + } + + // Focus on Current Item + ListView_SetItemState(m_ctlErrors, nIndex, LVIS_SELECTED | LVIS_FOCUSED, + LVIS_STATEIMAGEMASK); + + // Load the Menu + HMENU hMenu = ::LoadMenu(_Module.m_hInstResource, MAKEINTRESOURCE(IDR_ERROR_MENU)); + if (!hMenu) return 0; + + HMENU hSubMenu = GetSubMenu(hMenu, 0); + if (!hSubMenu) + { + DestroyMenu(hMenu); + return 0; + } + + // Get a COM Pointer to the current Error + INightSecErrorFixPtr pFix = (INightSecError*)m_ctlErrors.GetItemData(nIndex); + + if(pFix) + { + // Check if Fixable + BOOL bFixable = FALSE; + if(SUCCEEDED(pFix->get_Fixable(&bFixable)) && bFixable) + ::EnableMenuItem(hSubMenu, ID_ERROR_FIX, MF_BYCOMMAND | MF_ENABLED); + + // Check if Retryable + BOOL bRetryable = FALSE; + if(SUCCEEDED(pFix->get_Retryable(&bRetryable)) && bRetryable) + ::EnableMenuItem(hSubMenu, ID_ERROR_RETRY, MF_BYCOMMAND | MF_ENABLED); + } + + // Make the default (same as double-click) Retry + SetMenuDefaultItem(hSubMenu, ID_ERROR_RETRY, FALSE); + + // Show the Menu + ::TrackPopupMenu(hSubMenu, 0, ptMouse.x, ptMouse.y, 0, m_hWnd, NULL); + ::PostMessage(m_hWnd, WM_USER, 0, 0); + return 0; +} + +LRESULT CLogDlg::OnErrorFix(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + // Fix all selected items + int nPos = -1; + while((nPos = m_ctlErrors.GetNextItem(nPos, LVIS_SELECTED)) != -1) + FixItem(nPos); + + return 0; +} + +LRESULT CLogDlg::OnErrorRetry(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + // Retry all selected Items + int nPos = -1; + while((nPos = m_ctlErrors.GetNextItem(nPos, LVIS_SELECTED)) != -1) + RetryItem(nPos); + + return 0; +} + +LRESULT CLogDlg::OnErrorDelete(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + // Delete all selected items + int nPos = -1; + while((nPos = m_ctlErrors.GetNextItem(nPos, LVIS_SELECTED)) != -1) + RemoveItem(nPos); + + return 0; +} + +HRESULT CLogDlg::FixItem(int nIndex) +{ + USES_CONVERSION; + + // Extract COM Pointer from ListCtrl + INightSecErrorFixPtr pFix = (INightSecError*)m_ctlErrors.GetItemData(nIndex); + + if(pFix == NULL) + return 0; + + // Check if actually fixable + BOOL bFixable = FALSE; + if(FAILED(pFix->get_Fixable(&bFixable)) || !bFixable) + return 0; + + // Fix it + HCURSOR hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); + + HRESULT hr = pFix->Fix(); + + ::SetCursor(hOldCursor); + + INightSecErrorPtr pError = pFix; + + if(pError == NULL) + return 0; + + // Get New Error Messages + BSTR bsTemp; + pError->get_Description(&bsTemp); + + // Clean up newlines + replace(bsTemp, bsTemp + SysStringLen(bsTemp), L'\n', L' '); + replace(bsTemp, bsTemp + SysStringLen(bsTemp), L'\r', L' '); + + // Set Image and Text + LV_ITEM lv; + lv.mask = LVIF_IMAGE | LVIF_TEXT; + lv.iSubItem = 0; + lv.iItem = nIndex; + lv.pszText = OLE2T(bsTemp); + lv.iImage = SUCCEEDED(hr) ? 0 : 1; + + // Set right image and text for item + m_ctlErrors.SetItem(&lv); + + return hr; +} + +HRESULT CLogDlg::RetryItem(int nIndex) +{ + USES_CONVERSION; + + // Extract COM Pointer from List Ctrl + INightSecErrorFixPtr pFix = (INightSecError*)m_ctlErrors.GetItemData(nIndex); + + if(pFix == NULL) + return 0; + + // Check if we can actually Retry + BOOL bRetryable = FALSE; + if(FAILED(pFix->get_Retryable(&bRetryable)) || !bRetryable) + return 0; + + // Retry it + HCURSOR hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); + + HRESULT hr = pFix->Retry(); + + ::SetCursor(hOldCursor); + + INightSecErrorPtr pError = pFix; + + if(pError == NULL) + return 0; + + // Get new Error Messages + BSTR bsTemp; + pError->get_Description(&bsTemp); + + // Clean up newlines + replace(bsTemp, bsTemp + SysStringLen(bsTemp), L'\n', L' '); + replace(bsTemp, bsTemp + SysStringLen(bsTemp), L'\r', L' '); + + // Set Image and Text + LV_ITEM lv; + lv.mask = LVIF_IMAGE | LVIF_TEXT; + lv.iSubItem = 0; + lv.iItem = nIndex; + lv.pszText = OLE2T(bsTemp); + lv.iImage = SUCCEEDED(hr) ? IMAGE_OKAY : IMAGE_ERROR; + + // Set right image and text for item + m_ctlErrors.SetItem(&lv); + + return hr; +} + +bool CLogDlg::RemoveItem(int nIndex) +{ + // Release COM Ptr + INightSecError* pError = (INightSecError*)m_ctlErrors.GetItemData(nIndex); + if(pError) pError->Release(); + + // Remove it + return m_ctlErrors.DeleteItem(nIndex) ? true : false; +} + +void CLogDlg::Init(HWND hWndParent) +{ + m_hWndParent = hWndParent; +} |