/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: smonprop.cpp Abstract: Sysmon property page base class. --*/ #include "polyline.h" #include #include "smonprop.h" #include "genprop.h" #include "ctrprop.h" #include "grphprop.h" #include "srcprop.h" #include "appearprop.h" #include "unihelpr.h" #include "utils.h" #include "smonhelp.h" #include "globals.h" static ULONG aulControlIdToHelpIdMap[] = { IDC_CTRLIST, IDH_CTRLIST, // Data IDC_ADDCTR, IDH_ADDCTR, IDC_DELCTR, IDH_DELCTR, IDC_LINECOLOR, IDH_LINECOLOR, IDC_LINEWIDTH, IDH_LINEWIDTH, IDC_LINESTYLE, IDH_LINESTYLE, IDC_LINESCALE, IDH_LINESCALE, IDC_GALLERY_REPORT, IDH_GALLERY_REPORT, // General IDC_GALLERY_GRAPH, IDH_GALLERY_GRAPH, IDC_GALLERY_HISTOGRAM, IDH_GALLERY_HISTOGRAM, IDC_VALUEBAR, IDH_VALUEBAR, IDC_TOOLBAR, IDH_TOOLBAR, IDC_LEGEND, IDH_LEGEND, IDC_RPT_VALUE_DEFAULT, IDH_RPT_VALUE_DEFAULT, IDC_RPT_VALUE_MINIMUM, IDH_RPT_VALUE_MINIMUM, IDC_RPT_VALUE_MAXIMUM, IDH_RPT_VALUE_MAXIMUM, IDC_RPT_VALUE_AVERAGE, IDH_RPT_VALUE_AVERAGE, IDC_RPT_VALUE_CURRENT, IDH_RPT_VALUE_CURRENT, IDC_COMBOAPPEARANCE, IDH_COMBOAPPEARANCE, IDC_COMBOBORDERSTYLE, IDH_COMBOBORDERSTYLE, IDC_PERIODIC_UPDATE, IDH_PERIODIC_UPDATE, IDC_DISPLAY_INTERVAL, IDH_DISPLAY_INTERVAL, IDC_UPDATE_INTERVAL, IDH_UPDATE_INTERVAL, IDC_DUPLICATE_INSTANCE, IDH_DUPLICATE_INSTANCE, IDC_GRAPH_TITLE, IDH_GRAPH_TITLE, // Graph IDC_YAXIS_TITLE, IDH_YAXIS_TITLE, IDC_VERTICAL_GRID, IDH_VERTICAL_GRID, IDC_HORIZONTAL_GRID, IDH_HORIZONTAL_GRID, IDC_VERTICAL_LABELS, IDH_VERTICAL_LABELS, IDC_VERTICAL_MAX, IDH_VERTICAL_MAX, IDC_VERTICAL_MIN, IDH_VERTICAL_MIN, IDC_SRC_REALTIME, IDH_SRC_REALTIME, // Source IDC_SRC_LOGFILE, IDH_SRC_LOGFILE, IDC_SRC_SQL, IDH_SRC_SQL, IDC_LIST_LOGFILENAME, IDH_LIST_LOGFILENAME, IDC_ADDFILE, IDH_ADDFILE, IDC_REMOVEFILE, IDH_REMOVEFILE, IDC_LOGSET_COMBO, IDH_LOGSET_COMBO, IDC_DSN_COMBO, IDH_DSN_COMBO, IDC_TIMESELECTBTN, IDH_TIMESELECTBTN, IDC_TIMERANGE, IDH_TIMERANGE, IDC_COLOROBJECTS, IDH_COLOROBJECTS, IDC_FONTBUTTON, IDH_FONTBUTTON, IDC_COLORBUTTON, IDH_COLORBUTTON, IDC_COLORSAMPLE, IDH_COLORSAMPLE, IDC_FONTSAMPLE, IDH_FONTSAMPLE, 0,0 }; /* * CSysmonPropPageFactory::CSysmonPropPageFactory * CSysmonPropPageFactory::~CSysmonPropPageFactory * CSysmonPropPageFactory::QueryInterface * CSysmonPropPageFactory::AddRef * CSysmonPropPageFactory::Release */ CSysmonPropPageFactory::CSysmonPropPageFactory(INT nPageID) { m_cRef=0L; m_nPageID = nPageID; return; } CSysmonPropPageFactory::~CSysmonPropPageFactory(void) { return; } STDMETHODIMP CSysmonPropPageFactory::QueryInterface(REFIID riid, PPVOID ppv) { HRESULT hr = S_OK; try { *ppv=NULL; if (IID_IUnknown==riid || IID_IClassFactory==riid) { *ppv=this; AddRef(); } else { hr = E_NOINTERFACE; } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP_(ULONG) CSysmonPropPageFactory::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CSysmonPropPageFactory::Release(void) { if (0!=--m_cRef) return m_cRef; delete this; return 0; } /* * CSysmonPropPageFactory::CreateInstance * CSysmonPropPageFactory::LockServer */ STDMETHODIMP CSysmonPropPageFactory::CreateInstance( IN LPUNKNOWN pUnkOuter, IN REFIID riid, OUT PPVOID ppvObj ) { PCSysmonPropPage pObj; HRESULT hr = NOERROR; // // No aggregation supported // if (NULL != pUnkOuter) { return (CLASS_E_NOAGGREGATION); } switch (m_nPageID) { case GENERAL_PROPPAGE: pObj = new CGeneralPropPage(); break; case SOURCE_PROPPAGE: pObj = new CSourcePropPage(); break; case COUNTER_PROPPAGE: pObj = new CCounterPropPage(); break; case GRAPH_PROPPAGE: pObj = new CGraphPropPage(); break; case APPEAR_PROPPAGE: pObj = new CAppearPropPage(); break; default: pObj = NULL; } if (NULL == pObj) return E_OUTOFMEMORY; if (pObj->Init()) { try { *ppvObj = NULL; hr = pObj->QueryInterface(riid, ppvObj); } catch (...) { hr = E_POINTER; } } else { hr = E_UNEXPECTED; } //Kill the object if initial creation or Init failed. if (FAILED(hr)) { delete pObj; } else { InterlockedIncrement(&g_cObj); } return hr; } STDMETHODIMP CSysmonPropPageFactory::LockServer(BOOL fLock) { if (fLock) { InterlockedIncrement(&g_cLock); } else { InterlockedDecrement(&g_cLock); } return NOERROR; } /* * CSysmonPropPage implementation */ CSysmonPropPage::CSysmonPropPage(void) : m_cRef ( 0 ), m_hDlg ( NULL ), m_pIPropertyPageSite ( NULL ), m_ppISysmon ( NULL ), m_cObjects ( 0 ), m_cx ( 300 ), // Default width m_cy ( 100 ), // Default height m_fDirty ( FALSE ), m_fActive ( FALSE ), m_lcid ( LOCALE_USER_DEFAULT ), m_dwEditControl ( 0 ) { return; } CSysmonPropPage::~CSysmonPropPage(void) { if (NULL != m_hDlg) DestroyWindow(m_hDlg); FreeAllObjects(); ReleaseInterface(m_pIPropertyPageSite); return; } /* * CSysmonPropPage::QueryInterface * CSysmonPropPage::AddRef * CSysmonPropPage::Release */ STDMETHODIMP CSysmonPropPage::QueryInterface(REFIID riid, PPVOID ppv) { HRESULT hr = S_OK; try { *ppv=NULL; if (IID_IUnknown==riid || IID_IPropertyPage==riid) { *ppv=this; AddRef(); } else { hr = E_NOINTERFACE; } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP_(ULONG) CSysmonPropPage::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CSysmonPropPage::Release(void) { if (0 != --m_cRef) return m_cRef; InterlockedDecrement(&g_cObj); delete this; return 0; } /* * CSysmonPropPage::Init * * Purpose: * Performs initialization operations that might fail. * * Parameters: * None * * Return Value: * BOOL TRUE if initialization successful, FALSE * otherwise. */ BOOL CSysmonPropPage::Init(void) { //Nothing to do return TRUE; } /* * CSysmonPropPage::FreeAllObjects * * Purpose: * Releases all the objects from IPropertyPage::SetObjects * * Parameters: * None */ void CSysmonPropPage::FreeAllObjects(void) { UINT i; if (NULL==m_ppISysmon) return; for (i=0; i < m_cObjects; i++) ReleaseInterface(m_ppISysmon[i]); delete [] m_ppISysmon; m_ppISysmon =NULL; m_cObjects = 0; } /* * CSysmonPropPage::SetChange * * Purpose: * Set the page dirty flag to indicate a change * If page site is active, send status change to it. * * Parameters: * None */ void CSysmonPropPage::SetChange(void) { if (m_fActive) { m_fDirty=TRUE; if (NULL != m_pIPropertyPageSite) { m_pIPropertyPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY); } } } /* * CSysmonPropPage::SetPageSite * * Purpose: * Provides the property page with the IPropertyPageSite * that contains it. SetPageSite(NULL) will be called as * part of the close sequence. * * Parameters: * pPageSite LPPROPERTYPAGESITE pointer to the site. */ STDMETHODIMP CSysmonPropPage::SetPageSite( LPPROPERTYPAGESITE pPageSite ) { HRESULT hr = S_OK; if (NULL==pPageSite) ReleaseInterface(m_pIPropertyPageSite) else { HWND hDlg; RECT rc; LCID lcid; try { m_pIPropertyPageSite=pPageSite; m_pIPropertyPageSite->AddRef(); if (SUCCEEDED(m_pIPropertyPageSite->GetLocaleID(&lcid))) m_lcid=lcid; /* * Load the dialog and determine the size it will be to * return through GetPageSize. We just create the dialog * here and destroy it again to retrieve the size, * leaving Activate to create it for real. */ hDlg=CreateDialogParam(g_hInstance, MAKEINTRESOURCE(m_uIDDialog), GetDesktopWindow(), SysmonPropPageProc, 0L); // // If creation fails, use default values set in constructor // and return success status. if (NULL!=hDlg) { GetWindowRect(hDlg, &rc); m_cx=rc.right-rc.left; m_cy=rc.bottom-rc.top; DestroyWindow(hDlg); } } catch (...) { hr = E_POINTER; } } return hr; } /* * CSysmonPropPage::Activate * * Purpose: * Instructs the property page to create a window in which to * display its contents, using the given parent window and * rectangle. The window should be initially visible. * * Parameters: * hWndParent HWND of the parent window. * prc LPCRECT of the rectangle to use. * fModal BOOL indicating whether the frame is modal. */ STDMETHODIMP CSysmonPropPage::Activate( HWND hWndParent, LPCRECT prc, BOOL /* fModal */ ) { if (NULL!=m_hDlg) return (E_UNEXPECTED); m_hDlg=CreateDialogParam(g_hInstance, MAKEINTRESOURCE(m_uIDDialog), hWndParent, SysmonPropPageProc, (LPARAM)this); if (NULL==m_hDlg) { // // Return E_OUTOFMEMORY because caller of Activate might not // handle HRESULT_FROM_WIN32(GetLastError()); // return E_OUTOFMEMORY; } if (!InitControls()) { return E_OUTOFMEMORY; } if (!GetProperties()) { return E_OUTOFMEMORY; } // //Move the page into position and show it. // try { SetWindowPos(m_hDlg, NULL, prc->left, prc->top, 0, 0, SWP_NOSIZE ); } catch (...) { return E_POINTER; } m_fActive = TRUE; return NOERROR; } /* * CSysmonPropPage::Deactivate * * Purpose: * Instructs the property page to destroy its window that was * created in Activate. * * Parameters: * None */ STDMETHODIMP CSysmonPropPage::Deactivate(void) { if (NULL==m_hDlg) return (E_UNEXPECTED); DeinitControls(); DestroyWindow(m_hDlg); m_hDlg=NULL; m_fActive = FALSE; return NOERROR; } /* * CSysmonPropPage::GetPageInfo * * Purpose: * Fills a PROPPAGEINFO structure describing the page's size, * contents, and help information. * * Parameters: * pPageInfo LPPROPPAGEINFO to the structure to fill. */ STDMETHODIMP CSysmonPropPage::GetPageInfo( LPPROPPAGEINFO pPageInfo ) { IMalloc * pIMalloc; LPWSTR pTitle = NULL; ULONG ulTitleLen = 0; LPWSTR pBuf = NULL; pTitle = ResourceString(m_uIDTitle); if (pTitle) { ulTitleLen = wcslen(pTitle) + 1; if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) { return (E_FAIL); } pBuf = (LPWSTR)pIMalloc->Alloc(ulTitleLen * sizeof(WCHAR)); if (NULL != pBuf) { // // We already reserved an extra position for the null character // StringCchCopy(pBuf, ulTitleLen, pTitle); } pIMalloc->Release(); } try { pPageInfo->size.cx = m_cx; pPageInfo->size.cy = m_cy; pPageInfo->pszDocString = NULL; pPageInfo->pszHelpFile = NULL; pPageInfo->dwHelpContext= 0; pPageInfo->pszTitle = pBuf; } catch (...) { return E_POINTER; } return S_OK; } /* * CSysmonPropPage::SetObjects * * Purpose: * Identifies the objects that are being affected by this property * page (and all other pages in the frame). These are the object * to which to send new property values in the Apply member. * * Parameters: * cObjects ULONG number of objects * ppUnk IUnknown ** to the array of objects being * passed to the page. */ STDMETHODIMP CSysmonPropPage::SetObjects( IN ULONG cObjects, IN IUnknown **ppUnk ) { HRESULT hr = S_OK; FreeAllObjects(); if (0 != cObjects) { UINT i; m_ppISysmon = new ISystemMonitor * [(UINT)cObjects]; if (m_ppISysmon == NULL) return E_OUTOFMEMORY; try { for (i=0; i < cObjects; i++) { hr=ppUnk[i]->QueryInterface(IID_ISystemMonitor, (void **)&m_ppISysmon[i]); if (FAILED(hr)) { break; } } } catch (...) { hr = E_POINTER; } } if ( FAILED ( hr ) && NULL != m_ppISysmon ) { // // Ref count never incremented, so delete the array. // delete [] m_ppISysmon; m_ppISysmon = NULL; } if ( SUCCEEDED ( hr ) ) { m_cObjects=cObjects; } return hr; } /* * CSysmonPropPage::Show * * Purpose: * Instructs the page to show or hide its window created in * Activate. * * Parameters: * nCmdShow UINT to pass to ShowWindow. */ STDMETHODIMP CSysmonPropPage::Show(UINT nCmdShow) { if (NULL==m_hDlg) (E_UNEXPECTED); ShowWindow(m_hDlg, nCmdShow); // If showing page if (SW_SHOWNORMAL==nCmdShow || SW_SHOW==nCmdShow) { // Take the focus // (Have to delay so it isn't taken back) PostMessage(m_hDlg,WM_SETPAGEFOCUS,0,0); } return NOERROR; } /* * CSysmonPropPage::Move * * Purpose: * Instructs the property page to change its position. * * Parameters: * prc LPCRECT containing the new position. */ STDMETHODIMP CSysmonPropPage::Move( LPCRECT prc ) { HRESULT hr = S_OK; try { SetWindowPos(m_hDlg, NULL, prc->left, prc->top, 0, 0, SWP_NOSIZE ); } catch (...) { hr = E_POINTER; } return hr; } /* * CSysmonPropPage::IsPageDirty * * Purpose: * Asks the page if anything's changed in it, that is, if the * property values in the page are out of sync with the objects * under consideration. * * Parameters: * None * * Return Value: * HRESULT NOERROR if dirty, S_FALSE if not. */ STDMETHODIMP CSysmonPropPage::IsPageDirty(void) { return (m_fDirty ? S_OK : S_FALSE); } /* * CSysmonPropPage::Apply * * Purpose: * Instructs the page to send changes in its page to whatever * objects it knows about through SetObjects. This is the only * time the page should change the objects' properties, and not * when the value is changed on the page. * * Parameters: * None */ STDMETHODIMP CSysmonPropPage::Apply(void) { HRESULT hr = NOERROR; if ( 0 != m_cObjects ) { // Kill the focus in case a text field has it. This will trigger // the entry processing code. SetFocus(NULL); { CWaitCursor cursorWait; if (SetProperties()) { m_fDirty = FALSE; } else { hr = E_FAIL; } } } return hr; } /* * CSysmonPropPage::Help * * Purpose: * Invokes help for this property page when the user presses * the Help button. If you return NULLs for the help file * in GetPageInfo, the button will be grayed. Otherwise the * page can perform its own help here. * * Parameters: * pszHelpDir LPCOLESTR identifying the default location of * the help information * * Return Value: * HRESULT NOERROR to tell the frame that we've done our * own help. Returning an error code or S_FALSE * causes the frame to use any help information * in PROPPAGEINFO. */ STDMETHODIMP CSysmonPropPage::Help(LPCOLESTR /* pszHelpDir */ ) { /* * We can either provide help ourselves, or rely on the * information in PROPPAGEINFO. */ return (S_FALSE); } /* * CSysmonPropPage::TranslateAccelerator * * Purpose: * Provides the page with the messages that occur in the frame. * This gives the page to do whatever it wants with the message, * such as handle keyboard mnemonics. * * Parameters: * pMsg LPMSG containing the keyboard message. */ STDMETHODIMP CSysmonPropPage::TranslateAccelerator(LPMSG lpMsg) { BOOL fTakeIt = TRUE; BOOL fHandled = FALSE; HRESULT hr; HWND hwnd; if (lpMsg == NULL) return E_POINTER; // If TAB key if (lpMsg->message == WM_KEYDOWN ) { if ( lpMsg->wParam == VK_TAB && GetKeyState(VK_CONTROL) >= 0) { UINT uDir = GetKeyState(VK_SHIFT) >= 0 ? GW_HWNDNEXT : GW_HWNDPREV; hwnd = GetFocus(); if (IsChild(m_hDlg, hwnd)) { // Get top level child for controls with children, like combo. while (GetParent(hwnd) != m_hDlg) hwnd = GetParent(hwnd); // If this control is the last enabled tab stop, don't steal the TAB key do { hwnd = GetWindow(hwnd, uDir); if ( NULL == hwnd ) { fTakeIt = FALSE; break; } } while ((GetWindowLong(hwnd, GWL_STYLE) & (WS_DISABLED | WS_TABSTOP)) != WS_TABSTOP); } } /* fTakeIt is already TRUE. // else if Arrow key else if ( lpMsg->message == WM_KEYDOWN && ( lpMsg->wParam == VK_LEFT || lpMsg->wParam == VK_UP || lpMsg->wParam == VK_RIGHT || lpMsg->wParam == VK_DOWN ) ) { fTakeIt = TRUE; } */ // else if Return or Escape key else if ( lpMsg->wParam == VK_RETURN || lpMsg->wParam == VK_ESCAPE ) { fTakeIt = (lpMsg->wParam == VK_RETURN); if ( fTakeIt ) { hwnd = GetFocus(); if ( NULL == hwnd ) { fTakeIt = FALSE; } else { fTakeIt = IsChild(m_hDlg, hwnd); if ( fTakeIt ) { fTakeIt = (BOOL) SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON; } } } } } else if ( ( WM_KEYUP == lpMsg->message ) ) { fTakeIt = FALSE; } // if we should process the key if (fTakeIt) { // if the target is not one of our controls, change it so IsDialogMessage works if (!IsChild(m_hDlg, lpMsg->hwnd)) { hwnd = lpMsg->hwnd; lpMsg->hwnd = GetWindow(m_hDlg, GW_CHILD); fHandled = IsDialogMessage(m_hDlg, lpMsg); lpMsg->hwnd = hwnd; } else { fHandled = IsDialogMessage(m_hDlg, lpMsg); } } if (fHandled){ return S_OK; } else{ hr = m_pIPropertyPageSite->TranslateAccelerator(lpMsg); } return hr; } /* * CSysmonPropPage::EditProperty * * Purpose: * Sets focus to the control corresponding to the supplied DISPID. * * Parameters: * dispID DISPID of the property */ STDMETHODIMP CSysmonPropPage::EditProperty(DISPID dispID) { HRESULT hr; hr = EditPropertyImpl ( dispID ); if ( SUCCEEDED(hr)) { SetFocus ( GetDlgItem ( m_hDlg, m_dwEditControl ) ); m_dwEditControl = 0; } return hr; } /* * CSysmonPropPage::WndProc * * Purpose: * This is a default message processor that can be overriden by * a subclass to provide special message handling. * * Parameters: * pMsg LPMSG containing the keyboard message. */ BOOL CSysmonPropPage::WndProc ( UINT, // uMsg, WPARAM, // wParam, LPARAM // lParam ) { return FALSE; } /* * SysmonPropPageProc * * Purpose: * Dialog procedure for the Sysmon Property Page. */ INT_PTR APIENTRY CALLBACK SysmonPropPageProc( HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam ) { static WCHAR szObj[] = L"Object"; PCSysmonPropPage pObj = NULL; PMEASUREITEMSTRUCT pMI; HWND hwndTabCtrl; HWND hwndPropSheet; INT iCtrlID; WCHAR pszHelpFilePath[MAX_PATH * 2]; LPHELPINFO pInfo; UINT nLen; BOOL bReturn = FALSE; if ( NULL != hDlg ) { pObj = (PCSysmonPropPage)GetProp(hDlg, szObj); } switch (iMsg) { case WM_INITDIALOG: pObj=(PCSysmonPropPage)lParam; if ( NULL != pObj && NULL != hDlg ) { SetProp(hDlg, szObj, (HANDLE)lParam); hwndTabCtrl = ::GetParent(hDlg); hwndPropSheet = ::GetParent(hwndTabCtrl); SetWindowLongPtr(hwndPropSheet, GWL_EXSTYLE, GetWindowLongPtr(hwndPropSheet,GWL_EXSTYLE)|WS_EX_CONTEXTHELP); } bReturn = TRUE; break; case WM_DESTROY: if ( NULL != hDlg ) { RemoveProp(hDlg, szObj); } bReturn = TRUE; break; case WM_MEASUREITEM: pMI = (PMEASUREITEMSTRUCT)lParam; if ( NULL != pMI ) { pMI->itemWidth = 0 ; pMI->itemHeight = 16; } bReturn = TRUE; break; case WM_DRAWITEM: if ( NULL != pObj ) { pObj->DrawItem ((PDRAWITEMSTRUCT) lParam) ; } bReturn = TRUE; break; case WM_COMMAND: if ( NULL != pObj ) { pObj->DialogItemChange(LOWORD(wParam), HIWORD(wParam)); } bReturn = FALSE; break; case WM_SETPAGEFOCUS: if ( NULL != hDlg ) { SetFocus(hDlg); bReturn = TRUE; } break; case WM_CONTEXTMENU: if ( NULL != (HWND) wParam ) { iCtrlID = GetDlgCtrlID ( (HWND) wParam ); if ( 0 != iCtrlID ) { nLen = ::GetWindowsDirectory(pszHelpFilePath, 2*MAX_PATH); if ( 0 < nLen ) { StringCchCat(pszHelpFilePath, 2* MAX_PATH, L"\\help\\sysmon.hlp" ); bReturn = WinHelp( (HWND) wParam, pszHelpFilePath, HELP_CONTEXTMENU, (DWORD_PTR) aulControlIdToHelpIdMap); } } } // bReturn is FALSE by default break; case WM_HELP: if ( NULL != hDlg ) { pInfo = (LPHELPINFO)lParam; if ( NULL != pInfo ) { // Only display help for known context IDs. if ( 0 != pInfo->dwContextId ) { nLen = ::GetWindowsDirectory(pszHelpFilePath, 2*MAX_PATH); if ( 0 < nLen ) { StringCchCat(pszHelpFilePath, 2* MAX_PATH, L"\\help\\sysmon.hlp" ); bReturn = WinHelp ( hDlg, pszHelpFilePath, HELP_CONTEXTPOPUP, pInfo->dwContextId ); } } } } // bReturn is FALSE by default break; default: if ( NULL != pObj ) { bReturn = pObj->WndProc(iMsg, wParam, lParam); } } return bReturn; }