/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ /* helper.h This file defines the following macros helper classes and functions: Macros to check HRESULT CDlgHelper -- helper class to Enable/Check dialog Item, CMangedPage -- helper class for PropertyPage, It manages ReadOnly, SetModified, and ContextHelp CHelpDialog -- helper class for dialog with context help support CStrArray -- an array of pointer to CString It does NOT duplicate the string upon Add and It deletes the pointer during destruction It imports and exports SAFEARRAY CReadWriteLock -- class for share read or exclusive write lock CStrBox -- wrapper class for CListBox and CComboBox CIPAddress -- wrapper for IPAddress CFramedRoute -- Wrapper for FramedRoute CStrParse -- parses string for TimeOfDay FILE HISTORY: */ // helper functions for dialog and dialog items #ifndef _DLGHELPER_ #define _DLGHELPER_ #ifdef NOIMP #undef NOIMP #endif #define NOIMP {return E_NOTIMPL;} #ifdef SAYOK #undef SAYOK #endif #define SAYOK {return S_OK;} // to reduce the step to set VARIANT #define V__BOOL(v, v1)\ V_VT(v) = VT_BOOL, V_BOOL(v) = (v1) #define V__I4(v, v1)\ V_VT(v) = VT_I4, V_I4(v) = (v1) #define V__I2(v, v1)\ V_VT(v) = VT_I2, V_I2(v) = (v1) #define V__UI1(v, v1)\ V_VT(v) = VT_UI1, V_UI1(v) = (v1) #define V__BSTR(v, v1)\ V_VT(v) = VT_BSTR, V_BSTR(v) = (v1) #define V__ARRAY(v, v1)\ V_VT(v) = VT_ARRAY, V_ARRAY(v) = (v1) #define REPORT_ERROR(hr) \ TRACE(_T("**** ERROR RETURN <%s @line %d> -> %08lx\n"), \ __FILE__, __LINE__, hr)); \ ReportError(hr, 0, 0); #ifdef _DEBUG #define CHECK_HR(hr)\ {if(!CheckADsError(hr, FALSE, __FILE__, __LINE__)){goto L_ERR;}} #else #define CHECK_HR(hr)\ if FAILED(hr) goto L_ERR #endif #ifdef _DEBUG #define NOTINCACHE(hr)\ (CheckADsError(hr, TRUE, __FILE__, __LINE__)) #else #define NOTINCACHE(hr)\ (E_ADS_PROPERTY_NOT_FOUND == (hr)) #endif BOOL CheckADsError(HRESULT hr, BOOL fIgnoreAttrNotFound, PSTR file, int line); #ifdef _DEBUG #define TRACEAfxMessageBox(id) {\ TRACE(_T("AfxMessageBox <%s @line %d> ID: %d\n"), \ __FILE__, __LINE__, id); \ AfxMessageBox(id);}\ #else #define TRACEAfxMessageBox(id) AfxMessageBox(id) #endif // change string Name to CN=Name void DecorateName(LPWSTR outString, LPCWSTR inString); // change string Name to CN=Name HRESULT GetDSRoot(CString& RootString); // find name from DN for example LDAP://CN=userA,CN=users... returns userA void FindNameByDN(LPWSTR outString, LPCWSTR inString); class CDlgHelper { public: static void EnableDlgItem(CDialog* pDialog, int id, bool bEnable = true); static int GetDlgItemCheck(CDialog* pDialog, int id); static void SetDlgItemCheck(CDialog* pDialog, int id, int nCheck); }; struct CMMCNotify { CMMCNotify() : m_lNotifyHandle(0), m_lParam(0) {}; LONG_PTR m_lNotifyHandle; LPARAM m_lParam; HRESULT MMCNotify() { if(m_lNotifyHandle != 0 && m_lParam != 0) return MMCPropertyChangeNotify(m_lNotifyHandle, m_lParam); else return S_FALSE; }; }; class CManagedPage; // class CPageManager and CManagedPage together handle the situation when // the property sheet need to do some processing when OnApply function is called // on some of the pages class ATL_NO_VTABLE CPageManager : public CComObjectRootEx, public IUnknown { BEGIN_COM_MAP(CPageManager) COM_INTERFACE_ENTRY(IUnknown) END_COM_MAP() public: CPageManager(){ m_bCanCancel = TRUE; m_bModified = FALSE; m_bReadOnly = FALSE; m_dwFlags = 0;}; BOOL GetModified(){ return m_bModified;}; void SetModified(BOOL bModified){ m_bModified = bModified;}; void SetReadOnly(BOOL bReadOnly){ m_bReadOnly = bReadOnly;}; BOOL GetReadOnly(){ return m_bReadOnly;}; HRESULT MMCNotify() { return m_mmcNotify.MMCNotify();}; BOOL IfCanCancel() { return m_bCanCancel;}; void SetCanCancel(BOOL bCanCancel ) { m_bCanCancel = bCanCancel;}; void SetMMCNotify(LONG_PTR lNotifyHandle, LPARAM lParam) { // this should be called only once ASSERT(m_mmcNotify.m_lNotifyHandle == 0); ASSERT(m_mmcNotify.m_lParam == 0); ASSERT(lNotifyHandle != 0); ASSERT(lParam != 0); m_mmcNotify.m_lNotifyHandle = lNotifyHandle; m_mmcNotify.m_lParam = lParam; }; virtual BOOL OnApply(); virtual void OnCancel( ){}; virtual void OnOK( ){}; void AddPage(CManagedPage* pPage); void AddFlags(DWORD flags) { m_dwFlags |= flags;}; DWORD GetFlags() { return m_dwFlags;}; void ClearFlags() { m_dwFlags = 0;}; protected: BOOL m_bModified; BOOL m_bReadOnly; std::list m_listPages; DWORD m_dwFlags; CMMCNotify m_mmcNotify; BOOL m_bCanCancel; }; //============================================================================= // Global Help Table for many Dialog IDs // struct CGlobalHelpTable{ UINT nIDD; const DWORD* pdwTable; }; //============================================================================= // Page that handles Context Help, and talk with CPageManager to do // OnApply together // class CManagedPage : public CPropertyPage // talk back to property sheet { DECLARE_DYNCREATE(CManagedPage) // Implementation protected: // Generated message map functions //{{AFX_MSG(CManagedPage) afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() protected: CManagedPage() : CPropertyPage(){ // Need to save the original callback pointer because we are replacing // it with our own m_pfnOriginalCallback = m_psp.pfnCallback; }; public: CManagedPage(UINT nIDTemplate) : CPropertyPage(nIDTemplate) { m_bModified = FALSE; m_pHelpTable = NULL; m_nIDD = nIDTemplate; // Need to save the original callback pointer because we are replacing // it with our own m_pfnOriginalCallback = m_psp.pfnCallback; }; void SetModified( BOOL bModified = TRUE ) { if(m_spManager.p && !m_spManager->GetReadOnly()) // if NOT readonly { m_bModified = bModified; CPropertyPage::SetModified(bModified); // only set change if(bModified) m_spManager->SetModified(TRUE); } else { m_bModified = bModified; CPropertyPage::SetModified(bModified); } }; BOOL GetModified() { return m_bModified;}; virtual BOOL OnApply() { m_bModified = FALSE; BOOL bRet = TRUE; if(m_spManager.p && m_spManager->GetModified()) // prevent from entering more than once { bRet = m_spManager->OnApply(); } if(bRet) return CPropertyPage::OnApply(); else { SetModified(); // when user click on OK next time, OnApply Should be called again. if(m_spManager->IfCanCancel() != TRUE) CancelToClose(); // change cancel button to close button return bRet; } }; virtual void OnCancel( ) { if(m_spManager.p) // prevent from entering more than once m_spManager->OnCancel(); CPropertyPage::OnCancel(); }; virtual void OnOK( ) { if(m_spManager.p) // prevent from entering more than once m_spManager->OnOK(); CPropertyPage::OnOK(); }; void SetManager(CPageManager* pManager) { m_spManager = pManager;}; void AddFlags(DWORD flags) { if(m_spManager.p) m_spManager->AddFlags(flags);}; protected: // set help table: either call SetGHelpTable or call setHelpTable void SetGlobalHelpTable(CGlobalHelpTable** pGTable) { if(pGTable) { while((*pGTable)->nIDD && (*pGTable)->nIDD != m_nIDD) pGTable++; if((*pGTable)->nIDD) m_pHelpTable = (*pGTable)->pdwTable; } }; void SetHelpTable(DWORD* pTable){m_pHelpTable = pTable;}; #ifdef _DEBUG virtual void Dump( CDumpContext& dc ) const { dc << _T("CManagedPage"); }; #endif protected: CComPtr m_spManager; BOOL m_bModified; UINT m_nIDD; const DWORD* m_pHelpTable; public: static UINT CALLBACK PropSheetPageProc( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp ); void SetSelfDeleteCallback() { // tell MMC to hook the proc because we are running on a separate, // non MFC thread. m_psp.pfnCallback = PropSheetPageProc; // We also need to save a self-reference so that the static callback // function can recover a "this" pointer m_psp.lParam = (LONG_PTR)this; }; protected: LPFNPSPCALLBACK m_pfnOriginalCallback; }; //============================================================================= // Dialog that handles Context Help // class CHelpDialog : public CDialog // talk back to property sheet { DECLARE_DYNCREATE(CHelpDialog) // Implementation protected: // Generated message map functions //{{AFX_MSG(CHelpDialog) afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() protected: CHelpDialog() : CDialog(){}; public: CHelpDialog(UINT nIDTemplate, CWnd* pParent) : CDialog(nIDTemplate, pParent) { m_pHelpTable = NULL; m_nIDD = nIDTemplate; }; protected: // set help table: either call SetGHelpTable or call setHelpTable void SetGlobalHelpTable(CGlobalHelpTable** pGTable) { if(pGTable) { while((*pGTable)->nIDD && (*pGTable)->nIDD != m_nIDD) pGTable++; if((*pGTable)->nIDD) m_pHelpTable = (*pGTable)->pdwTable; } }; void SetHelpTable(DWORD* pTable){m_pHelpTable = pTable;}; #ifdef _DEBUG virtual void Dump( CDumpContext& dc ) const { dc << _T("CHelpDialog"); }; #endif protected: UINT m_nIDD; const DWORD* m_pHelpTable; }; #include class CStrArray : public CArray< CString*, CString* > { public: CStrArray(SAFEARRAY* pSA = NULL); CStrArray(const CStrArray& sarray); CString* AddByRID(UINT rID); int Find(const CString& Str) const; int DeleteAll(); virtual ~CStrArray(); operator SAFEARRAY*(); CStrArray& operator = (const CStrArray& sarray); bool AppendSA(SAFEARRAY* pSA); }; class CDWArray : public CArray< DWORD, DWORD > { public: CDWArray(){}; CDWArray(const CDWArray& dwarray); int Find(const DWORD dw) const; int DeleteAll(){ RemoveAll(); return 0;}; virtual ~CDWArray(){RemoveAll();}; CDWArray& operator = (const CDWArray& dwarray); }; // a lock to allow multiple read access exclusive or only one write access class CReadWriteLock // sharable read, exclusive write { public: CReadWriteLock() : m_nRead(0) { #ifdef _DEBUG d_bWrite = false; #endif }; void EnterRead() { TRACE(_T("Entering Read Lock ...")); m_csRead.Lock(); if (!m_nRead++) m_csWrite.Lock(); m_csRead.Unlock(); TRACE(_T("Entered Read Lock\n")); }; void LeaveRead() { TRACE(_T("Leaving Read Lock ...")); m_csRead.Lock(); ASSERT(m_nRead > 0); if (!--m_nRead) m_csWrite.Unlock(); m_csRead.Unlock(); TRACE(_T("Left Read Lock\n")); }; void EnterWrite() { TRACE(_T("Entering Write Lock ...")); m_csWrite.Lock(); TRACE(_T("Entered Write Lock\n")); #ifdef _DEBUG d_bWrite = true; #endif }; void LeaveWrite() { #ifdef _DEBUG d_bWrite = false; #endif m_csWrite.Unlock(); TRACE(_T("Left Write Lock\n")); }; public: #ifdef _DEBUG bool d_bWrite; #endif protected: CCriticalSection m_csRead; CCriticalSection m_csWrite; int m_nRead; }; // to manage a list box/ combo box template class CStrBox { public: CStrBox(CDialog* pDialog, int id, CStrArray& Strings) : m_Strings(Strings), m_id(id) { m_pDialog = pDialog; m_pBox = NULL; }; int Fill() { m_pBox = (CBox*)m_pDialog->GetDlgItem(m_id); ASSERT(m_pBox); m_pBox->ResetContent(); int count = m_Strings.GetSize(); int index; for(int i = 0; i < count; i++) { index = m_pBox->AddString(*m_Strings[(INT_PTR)i]); m_pBox->SetItemDataPtr(index, m_Strings[(INT_PTR)i]); } return count; }; int DeleteSelected() { int index; ASSERT(m_pBox); index = m_pBox->GetCurSel(); // if there is any selected if( index != LB_ERR ) { CString* pStr; pStr = (CString*)m_pBox->GetItemDataPtr(index); // remove the entry from the box m_pBox->DeleteString(index); // find the string in the String array int count = m_Strings.GetSize(); for(int i = 0; i < count; i++) { if (m_Strings[(INT_PTR)i] == pStr) break; } ASSERT(i < count); // remove the string from the string array m_Strings.RemoveAt(i); index = i; delete pStr; } return index; }; int AddString(CString* pStr) // the pStr needs to dynamically allocated { int index; ASSERT(m_pBox && pStr); index = m_pBox->AddString(*pStr); m_pBox->SetItemDataPtr(index, pStr); return m_Strings.Add(pStr); }; int Select(int arrayindex) // the pStr needs to dynamically allocated { if(arrayindex < m_Strings.GetSize()) return m_pBox->SelectString(0, *m_Strings[(INT_PTR)arrayindex]); else return CB_ERR; }; void Enable(BOOL b) // the pStr needs to dynamically allocated { ASSERT(m_pBox); m_pBox->EnableWindow(b); }; int GetSelected() // it returns the index where the { int index; ASSERT(m_pBox); index = m_pBox->GetCurSel(); // if there is any selected if( index != LB_ERR ) { CString* pStr; pStr = (CString*)m_pBox->GetItemDataPtr(index); // find the string in the String array int count = m_Strings.GetSize(); for(int i = 0; i < count; i++) { if (m_Strings[(INT_PTR)i] == pStr) break; } ASSERT(i < count); index = i; } return index; }; CBox* m_pBox; protected: int m_id; CStrArray& m_Strings; CDialog* m_pDialog; }; // class to take care of ip address class CIPAddress { public: CIPAddress(DWORD address = 0) { m_dwAddress = address; }; // CIPAddress(const CString& strAddress){}; operator DWORD() { return m_dwAddress;}; operator CString() { CString str; WORD hi = HIWORD(m_dwAddress); WORD lo = LOWORD(m_dwAddress); str.Format(_T("%-d.%-d.%-d.%d"), HIBYTE(hi), LOBYTE(hi), HIBYTE(lo), LOBYTE(lo)); return str; }; DWORD m_dwAddress; }; // format of framedroute: mask dest metric ; mask and dest in dot format class CFramedRoute { public: void SetRoute(CString* pRoute) { m_pStrRoute = pRoute; m_pStrRoute->TrimLeft(); m_pStrRoute->TrimRight(); m_iFirstSpace = m_pStrRoute->Find(_T(' ')) ; m_iLastSpace = m_pStrRoute->ReverseFind(_T(' ')) ; }; CString& GetDest(CString& dest) const { int i = m_pStrRoute->Find(_T('/')); if(i == -1) i = m_iFirstSpace; dest = m_pStrRoute->Left(i); return dest; }; CString& GetNextStop(CString& nextStop) const { nextStop = m_pStrRoute->Mid(m_iFirstSpace + 1, m_iLastSpace - m_iFirstSpace -1 ); return nextStop; }; CString& GetPrefixLength(CString& prefixLength) const { int i = m_pStrRoute->Find(_T('/')); if( i != -1) { prefixLength = m_pStrRoute->Mid(i + 1, m_iFirstSpace - i - 1); } else prefixLength = _T(""); return prefixLength; }; CString& GetMetric(CString& metric) const { metric = m_pStrRoute->Mid(m_iLastSpace + 1); return metric; }; protected: // WARNING: the string is not copied, so user need to make sure the origin is valid CString* m_pStrRoute; int m_iFirstSpace; int m_iLastSpace; }; class CStrParser { public: CStrParser(LPCTSTR pStr = NULL) : m_pStr(pStr) { } // get the current string position LPCTSTR GetStr() const { return m_pStr;}; void SetStr(LPCTSTR pStr) { m_pStr = pStr;}; // find a unsigned interger and return it, -1 == not found int GetUINT() { UINT ret = 0; while((*m_pStr < _T('0') || *m_pStr > _T('9')) && *m_pStr != _T('\0')) m_pStr++; if(*m_pStr == _T('\0')) return -1; while(*m_pStr >= _T('0') && *m_pStr <= _T('9')) { ret = ret * 10 + *m_pStr - _T('0'); m_pStr++; } return ret; }; // find c and skip it int GotoAfter(TCHAR c) { int ret = 0; // go until find c or end of string while(*m_pStr != c && *m_pStr != _T('\0')) m_pStr++, ret++; // if found if(*m_pStr == c) m_pStr++, ret++; else ret = -1; return ret; }; // skip blank characters space tab void SkipBlank() { while((*m_pStr == _T(' ') || *m_pStr == _T('\t')) && *m_pStr != _T('\0')) m_pStr++; }; // check to see if the first character is '0'-'6' for Monday(0) to Sunday(6) int DayOfWeek() { SkipBlank(); if(*m_pStr >= _T('0') && *m_pStr <= _T('6')) return (*m_pStr++ - _T('0')); else return -1; // not day of week }; protected: LPCTSTR m_pStr; private: CString _strTemp; }; void ReportError(HRESULT hr, int nStr, HWND hWnd); void ReportError(HRESULT hr, LPCTSTR Str, HWND hWnd); UINT ReportErrorEx(HRESULT hr, int nStr, HWND hWnd, UINT MB_flags); UINT ReportErrorEx(HRESULT hr, LPCTSTR Str, HWND hWnd, UINT MB_flags); // number of characters void AFXAPI DDV_MinChars(CDataExchange* pDX, CString const& value, int nChars); #endif