435 lines
8.6 KiB
C++
435 lines
8.6 KiB
C++
// This is a part of the Active Template Library.
|
|
// Copyright (C) 1996-1998 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Active Template Library Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Active Template Library product.
|
|
|
|
#ifndef __ATLAPP_H__
|
|
#define __ATLAPP_H__
|
|
|
|
#ifndef __cplusplus
|
|
#error ATL requires C++ compilation (use a .cpp suffix)
|
|
#endif
|
|
|
|
#ifndef __ATLBASE_H__
|
|
#error atlapp.h requires atlbase.h to be included first
|
|
#endif
|
|
|
|
namespace ATL
|
|
{
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Forward declarations
|
|
|
|
class CMessageFilter;
|
|
class CUpdateUIObject;
|
|
class CMessageLoop;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Collection helpers - CSimpleArray & CSimpleMap for ATL 2.0/2.1
|
|
|
|
#if (_ATL_VER < 0x0300)
|
|
|
|
#ifndef ATLASSERT
|
|
#define ATLASSERT(expr) _ASSERTE(expr)
|
|
#endif
|
|
|
|
#ifndef ATLTRACE2
|
|
#define ATLTRACE2(cat, lev, msg) ATLTRACE(msg)
|
|
#endif
|
|
|
|
#ifndef ATLINLINE
|
|
#define ATLINLINE inline
|
|
#endif
|
|
|
|
template <class T>
|
|
class CSimpleArray
|
|
{
|
|
public:
|
|
T* m_aT;
|
|
int m_nSize;
|
|
int m_nAllocSize;
|
|
|
|
// Construction/destruction
|
|
CSimpleArray() : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
|
|
{ }
|
|
|
|
~CSimpleArray()
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
// Operations
|
|
int GetSize() const
|
|
{
|
|
return m_nSize;
|
|
}
|
|
BOOL Add(T& t)
|
|
{
|
|
if(m_nSize == m_nAllocSize)
|
|
{
|
|
T* aT;
|
|
int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2);
|
|
aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T));
|
|
if(aT == NULL)
|
|
return FALSE;
|
|
m_nAllocSize = nNewAllocSize;
|
|
m_aT = aT;
|
|
}
|
|
m_nSize++;
|
|
SetAtIndex(m_nSize - 1, t);
|
|
return TRUE;
|
|
}
|
|
BOOL Remove(T& t)
|
|
{
|
|
int nIndex = Find(t);
|
|
if(nIndex == -1)
|
|
return FALSE;
|
|
return RemoveAt(nIndex);
|
|
}
|
|
BOOL RemoveAt(int nIndex)
|
|
{
|
|
if(nIndex != (m_nSize - 1))
|
|
memmove((void*)&m_aT[nIndex], (void*)&m_aT[nIndex + 1], (m_nSize - (nIndex + 1)) * sizeof(T));
|
|
m_nSize--;
|
|
return TRUE;
|
|
}
|
|
void RemoveAll()
|
|
{
|
|
if(m_nSize > 0)
|
|
{
|
|
free(m_aT);
|
|
m_aT = NULL;
|
|
m_nSize = 0;
|
|
m_nAllocSize = 0;
|
|
}
|
|
}
|
|
T& operator[] (int nIndex) const
|
|
{
|
|
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
|
|
return m_aT[nIndex];
|
|
}
|
|
T* GetData() const
|
|
{
|
|
return m_aT;
|
|
}
|
|
|
|
// Implementation
|
|
void SetAtIndex(int nIndex, T& t)
|
|
{
|
|
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
|
|
m_aT[nIndex] = t;
|
|
}
|
|
int Find(T& t) const
|
|
{
|
|
for(int i = 0; i < m_nSize; i++)
|
|
{
|
|
if(m_aT[i] == t)
|
|
return i;
|
|
}
|
|
return -1; // not found
|
|
}
|
|
};
|
|
|
|
// for arrays of simple types
|
|
template <class T>
|
|
class CSimpleValArray : public CSimpleArray< T >
|
|
{
|
|
public:
|
|
BOOL Add(T t)
|
|
{
|
|
return CSimpleArray< T >::Add(t);
|
|
}
|
|
BOOL Remove(T t)
|
|
{
|
|
return CSimpleArray< T >::Remove(t);
|
|
}
|
|
T operator[] (int nIndex) const
|
|
{
|
|
return CSimpleArray< T >::operator[](nIndex);
|
|
}
|
|
};
|
|
|
|
|
|
// intended for small number of simple types or pointers
|
|
template <class TKey, class TVal>
|
|
class CSimpleMap
|
|
{
|
|
public:
|
|
TKey* m_aKey;
|
|
TVal* m_aVal;
|
|
int m_nSize;
|
|
|
|
// Construction/destruction
|
|
CSimpleMap() : m_aKey(NULL), m_aVal(NULL), m_nSize(0)
|
|
{ }
|
|
|
|
~CSimpleMap()
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
// Operations
|
|
int GetSize() const
|
|
{
|
|
return m_nSize;
|
|
}
|
|
BOOL Add(TKey key, TVal val)
|
|
{
|
|
TKey* pKey;
|
|
pKey = (TKey*)realloc(m_aKey, (m_nSize + 1) * sizeof(TKey));
|
|
if(pKey == NULL)
|
|
return FALSE;
|
|
m_aKey = pKey;
|
|
TVal* pVal;
|
|
pVal = (TVal*)realloc(m_aVal, (m_nSize + 1) * sizeof(TVal));
|
|
if(pVal == NULL)
|
|
return FALSE;
|
|
m_aVal = pVal;
|
|
m_nSize++;
|
|
SetAtIndex(m_nSize - 1, key, val);
|
|
return TRUE;
|
|
}
|
|
BOOL Remove(TKey key)
|
|
{
|
|
int nIndex = FindKey(key);
|
|
if(nIndex == -1)
|
|
return FALSE;
|
|
if(nIndex != (m_nSize - 1))
|
|
{
|
|
memmove((void*)&m_aKey[nIndex], (void*)&m_aKey[nIndex + 1], (m_nSize - (nIndex + 1)) * sizeof(TKey));
|
|
memmove((void*)&m_aVal[nIndex], (void*)&m_aVal[nIndex + 1], (m_nSize - (nIndex + 1)) * sizeof(TVal));
|
|
}
|
|
TKey* pKey;
|
|
pKey = (TKey*)realloc(m_aKey, (m_nSize - 1) * sizeof(TKey));
|
|
if(pKey != NULL || m_nSize == 1)
|
|
m_aKey = pKey;
|
|
TVal* pVal;
|
|
pVal = (TVal*)realloc(m_aVal, (m_nSize - 1) * sizeof(TVal));
|
|
if(pVal != NULL || m_nSize == 1)
|
|
m_aVal = pVal;
|
|
m_nSize--;
|
|
return TRUE;
|
|
}
|
|
void RemoveAll()
|
|
{
|
|
if(m_nSize > 0)
|
|
{
|
|
free(m_aKey);
|
|
free(m_aVal);
|
|
m_aKey = NULL;
|
|
m_aVal = NULL;
|
|
m_nSize = 0;
|
|
}
|
|
}
|
|
BOOL SetAt(TKey key, TVal val)
|
|
{
|
|
int nIndex = FindKey(key);
|
|
if(nIndex == -1)
|
|
return FALSE;
|
|
SetAtIndex(nIndex, key, val);
|
|
return TRUE;
|
|
}
|
|
TVal Lookup(TKey key) const
|
|
{
|
|
int nIndex = FindKey(key);
|
|
if(nIndex == -1)
|
|
return NULL; // must be able to convert
|
|
return GetValueAt(nIndex);
|
|
}
|
|
TKey ReverseLookup(TVal val) const
|
|
{
|
|
int nIndex = FindVal(val);
|
|
if(nIndex == -1)
|
|
return NULL; // must be able to convert
|
|
return GetKeyAt(nIndex);
|
|
}
|
|
TKey& GetKeyAt(int nIndex) const
|
|
{
|
|
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
|
|
return m_aKey[nIndex];
|
|
}
|
|
TVal& GetValueAt(int nIndex) const
|
|
{
|
|
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
|
|
return m_aVal[nIndex];
|
|
}
|
|
|
|
// Implementation
|
|
void SetAtIndex(int nIndex, TKey& key, TVal& val)
|
|
{
|
|
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
|
|
m_aKey[nIndex] = key;
|
|
m_aVal[nIndex] = val;
|
|
}
|
|
int FindKey(TKey& key) const
|
|
{
|
|
for(int i = 0; i < m_nSize; i++)
|
|
{
|
|
if(m_aKey[i] == key)
|
|
return i;
|
|
}
|
|
return -1; // not found
|
|
}
|
|
int FindVal(TVal& val) const
|
|
{
|
|
for(int i = 0; i < m_nSize; i++)
|
|
{
|
|
if(m_aVal[i] == val)
|
|
return i;
|
|
}
|
|
return -1; // not found
|
|
}
|
|
};
|
|
|
|
// WM_FORWARDMSG - used to forward a message to another window for processing
|
|
// WPARAM - DWORD dwUserData - defined by user
|
|
// LPARAM - LPMSG pMsg - a pointer to the MSG structure
|
|
// return value - 0 if the message was not processed, nonzero if it was
|
|
#define WM_FORWARDMSG 0x037F
|
|
|
|
#endif //(_ATL_VER < 0x0300)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMessageFilter - Interface for message filter support
|
|
|
|
class ATL_NO_VTABLE CMessageFilter
|
|
{
|
|
public:
|
|
virtual BOOL PreTranslateMessage(MSG* pMsg) = 0;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CUpdateUIObject - Interface for update UI support
|
|
|
|
class ATL_NO_VTABLE CUpdateUIObject
|
|
{
|
|
public:
|
|
virtual BOOL DoUpdate() = 0;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CMessageLoop - message loop implementation
|
|
|
|
class CMessageLoop
|
|
{
|
|
public:
|
|
CSimpleArray<CMessageFilter*> m_aMsgFilter;
|
|
CSimpleArray<CUpdateUIObject*> m_aUpdateUI;
|
|
MSG m_msg;
|
|
|
|
// Message filter operations
|
|
BOOL AddMessageFilter(CMessageFilter* pMessageFilter)
|
|
{
|
|
return m_aMsgFilter.Add(pMessageFilter);
|
|
}
|
|
BOOL RemoveMessageFilter(CMessageFilter* pMessageFilter)
|
|
{
|
|
return m_aMsgFilter.Remove(pMessageFilter);
|
|
}
|
|
// Update UI operations
|
|
BOOL AddUpdateUI(CUpdateUIObject* pUpdateUI)
|
|
{
|
|
return m_aUpdateUI.Add(pUpdateUI);
|
|
}
|
|
BOOL RemoveUpdateUI(CUpdateUIObject* pUpdateUI)
|
|
{
|
|
return m_aUpdateUI.Remove(pUpdateUI);
|
|
}
|
|
// message loop
|
|
int Run()
|
|
{
|
|
BOOL bDoIdle = TRUE;
|
|
int nIdleCount = 0;
|
|
BOOL bRet;
|
|
|
|
for(;;)
|
|
{
|
|
while(!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE) && bDoIdle)
|
|
{
|
|
if(!OnIdle(nIdleCount++))
|
|
bDoIdle = FALSE;
|
|
}
|
|
|
|
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
|
|
|
|
if(bRet == -1)
|
|
{
|
|
ATLTRACE2(atlTraceWindowing, 0, _T("::GetMessage returned -1 (error)\n"));
|
|
continue; // error, don't process
|
|
}
|
|
else if(!bRet)
|
|
{
|
|
ATLTRACE2(atlTraceWindowing, 0, _T("CMessageLoop::Run - exiting\n"));
|
|
break; // WM_QUIT, exit message loop
|
|
}
|
|
|
|
if(!PreTranslateMessage(&m_msg))
|
|
{
|
|
::TranslateMessage(&m_msg);
|
|
::DispatchMessage(&m_msg);
|
|
}
|
|
|
|
if(IsIdleMessage(&m_msg))
|
|
{
|
|
bDoIdle = TRUE;
|
|
nIdleCount = 0;
|
|
}
|
|
}
|
|
|
|
return (int)m_msg.wParam;
|
|
}
|
|
|
|
static BOOL IsIdleMessage(MSG* pMsg)
|
|
{
|
|
// These messages should NOT cause idle processing
|
|
switch(pMsg->message)
|
|
{
|
|
case WM_MOUSEMOVE:
|
|
#ifndef UNDER_CE
|
|
case WM_NCMOUSEMOVE:
|
|
#endif //!UNDER_CE
|
|
case WM_PAINT:
|
|
case 0x0118: // WM_SYSTIMER (caret blink)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Overrideables
|
|
// Override to change message filtering
|
|
virtual BOOL PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// loop backwards
|
|
for(int i = m_aMsgFilter.GetSize() - 1; i >= 0; i--)
|
|
{
|
|
CMessageFilter* pMessageFilter = m_aMsgFilter[i];
|
|
if(pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg))
|
|
return TRUE;
|
|
}
|
|
return FALSE; // not translated
|
|
}
|
|
// override to change idle UI updates
|
|
virtual BOOL OnIdle(int /*nIdleCount*/)
|
|
{
|
|
for(int i = 0; i < m_aUpdateUI.GetSize(); i++)
|
|
{
|
|
CUpdateUIObject* pUpdateUI = m_aUpdateUI[i];
|
|
if(pUpdateUI != NULL)
|
|
pUpdateUI->DoUpdate();
|
|
}
|
|
return FALSE; // don't continue
|
|
}
|
|
};
|
|
|
|
|
|
}; //namespace ATL
|
|
|
|
#endif // __ATLAPP_H__
|