Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

754 lines
16 KiB

/**********************************************************************/
/** 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<CComSingleThreadModel>,
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<CManagedPage*> 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<CPageManager> 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 <afxtempl.h>
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 CBox>
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