windows-nt/Source/XPSP1/NT/shell/ext/mlang/util.h
2020-09-26 16:20:57 +08:00

341 lines
7 KiB
C++

// Util.h : Helper functions and classes
#ifndef __UTIL_H_
#define __UTIL_H_
#include "mlatl.h"
extern class CMLAlloc* g_pMalloc;
/////////////////////////////////////////////////////////////////////////////
// CMLAlloc
class CMLAlloc
{
public:
CMLAlloc(void);
~CMLAlloc(void);
void* Alloc(ULONG cb);
void* Realloc(void* pv, ULONG cb);
void Free(void* pv);
private:
IMalloc* m_pIMalloc;
};
/////////////////////////////////////////////////////////////////////////////
// CMLList
class CMLList
{
public:
inline CMLList(int cbCell, int cbIncrement);
inline ~CMLList(void);
HRESULT Add(void** ppv);
HRESULT Remove(void* pv);
struct CCell
{
CCell* m_pNext;
};
protected:
inline void AssertPV(void*pv) const;
inline void* MemAlloc(ULONG cb) {return ::g_pMalloc->Alloc(cb);}
inline void* MemRealloc(void* pv, ULONG cb) {return ::g_pMalloc->Realloc(pv, cb);}
inline void MemFree(void* pv) {::g_pMalloc->Free(pv);}
private:
const int m_cbCell; // The size, in bytes, of a cell
const int m_cbIncrement; // The size, in bytes, to increase the buffer at a time
CCell* m_pBuf; // Pointer to the buffer
int m_cCell; // The number of cells allocated
CCell* m_pFree; // Pointer to a cell the top of free link
};
CMLList::CMLList(int cbCell, int cbIncrement) :
m_cbCell(cbCell),
m_cbIncrement(cbIncrement),
m_pBuf(NULL),
m_cCell(0),
m_pFree(NULL)
{
ASSERT(cbCell >= sizeof(CCell));
ASSERT(cbIncrement >= cbCell);
}
CMLList::~CMLList(void)
{
if (m_pBuf)
{
#ifdef DEBUG
int cCell = 0;
for (CCell* pCell = m_pFree; pCell; pCell = pCell->m_pNext)
{
if (++cCell > m_cCell)
{
ASSERT(FALSE); // Free link is broken
break;
}
}
ASSERT(cCell < m_cCell); // Memory leak!?
#endif
MemFree(m_pBuf);
}
}
void CMLList::AssertPV(void*pv) const
{
ASSERT(pv >= m_pBuf);
ASSERT(pv < m_pBuf + m_cbCell * m_cCell);
ASSERT(((CCell*)pv - m_pBuf) % m_cbCell == 0);
}
/////////////////////////////////////////////////////////////////////////////
// CMLListLru
class CMLListLru : public CMLList
{
public:
inline CMLListLru(int cbCell, int cbIncrement);
inline ~CMLListLru(void);
HRESULT Add(void** ppv);
HRESULT Remove(void* pv);
inline HRESULT Top(void** ppv) const;
inline HRESULT Next(void* pv, void** ppv) const;
typedef CMLList::CCell CCell;
private:
CCell* m_pTop;
};
CMLListLru::CMLListLru(int cbCell, int cbIncrement) :
CMLList(cbCell, cbIncrement),
m_pTop(NULL)
{
}
CMLListLru::~CMLListLru(void)
{
#ifdef DEBUG
ASSERT(!m_pTop); // Memory Leak?
while (m_pTop)
Remove(m_pTop);
#endif
}
HRESULT CMLListLru::Top(void** ppv) const
{
*ppv = (void*)m_pTop;
return S_OK;
}
HRESULT CMLListLru::Next(void* pv, void** ppv) const
{
AssertPV(pv);
const CCell* const pCell = (const CCell* const)pv;
if (pCell->m_pNext)
AssertPV(pCell->m_pNext);
*ppv = (void*)pCell->m_pNext;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CMLListFast - double linked list
class CMLListFast : public CMLList
{
public:
inline CMLListFast(int cbCell, int cbIncrement);
inline ~CMLListFast(void);
HRESULT Add(void** ppv);
HRESULT Remove(void* pv);
inline HRESULT Top(void** ppv) const;
inline HRESULT Bottom(void** ppv) const;
inline HRESULT Next(void* pv, void** ppv) const;
inline HRESULT Prev(void* pv, void** ppv) const;
struct CCell : public CMLList::CCell
{
CCell* m_pPrev;
};
private:
CCell* m_pTop;
};
CMLListFast::CMLListFast(int cbCell, int cbIncrement) :
CMLList(cbCell, cbIncrement),
m_pTop(NULL)
{
ASSERT(cbCell >= sizeof(CCell));
}
CMLListFast::~CMLListFast(void)
{
#ifdef DEBUG
ASSERT(!m_pTop); // Memory Leak?
while (m_pTop)
Remove(m_pTop);
#endif
}
HRESULT CMLListFast::Top(void** ppv) const
{
*ppv = (void*)m_pTop;
return S_OK;
}
HRESULT CMLListFast::Bottom(void** ppv) const
{
if (m_pTop)
{
return Prev(m_pTop, ppv);
}
else
{
*ppv = NULL;
return S_OK;
}
}
HRESULT CMLListFast::Next(void* pv, void** ppv) const
{
AssertPV(pv);
const CCell* const pCell = (const CCell* const)pv;
if (pCell->m_pNext)
AssertPV(pCell->m_pNext);
*ppv = (void*)pCell->m_pNext;
return S_OK;
}
HRESULT CMLListFast::Prev(void* pv, void** ppv) const
{
AssertPV(pv);
const CCell* const pCell = (const CCell* const)pv;
if (pCell->m_pPrev)
AssertPV(pCell->m_pPrev);
*ppv = (void*)pCell->m_pPrev;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CFireConnection
template <class T, const IID* piid>
class CFireConnection
{
public:
inline CFireConnection(HRESULT& rhr);
inline CFireConnection(HRESULT& rhr, IUnknown* const pUnk);
inline ~CFireConnection(void);
inline BOOL Next(void);
inline T* Sink(void);
protected:
HRESULT* const m_phr;
IEnumConnections* m_pEnumConn;
CONNECTDATA m_cd;
T* m_pSink;
};
template <class T, const IID* piid>
CFireConnection<T, piid>::CFireConnection(HRESULT& rhr) :
m_phr(&rhr),
m_pEnumConn(NULL),
m_pSink(NULL)
{
ASSERT_THIS;
ASSERT_READ_PTR(piid);
ASSERT_WRITE_PTR(m_phr);
*m_phr = S_OK;
}
template <class T, const IID* piid>
CFireConnection<T, piid>::CFireConnection(HRESULT& rhr, IUnknown* const pUnk) :
m_phr(&rhr),
m_pEnumConn(NULL),
m_pSink(NULL)
{
ASSERT_THIS;
ASSERT_READ_PTR(piid);
ASSERT_WRITE_PTR(m_phr);
ASSERT_READ_PTR(pUnk);
IConnectionPointContainer* pcpc;
if (SUCCEEDED(*m_phr = pUnk->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc)))
{
ASSERT_READ_PTR(pcpc);
IConnectionPoint* pcp;
if (SUCCEEDED(*m_phr = pcpc->FindConnectionPoint(*piid, &pcp)))
{
ASSERT_READ_PTR(pcp);
if (SUCCEEDED(*m_phr = pcp->EnumConnections(&m_pEnumConn)))
{
ASSERT_READ_PTR(m_pEnumConn);
}
else
{
m_pEnumConn = NULL;
}
pcp->Release();
}
pcpc->Release();
}
}
template <class T, const IID* piid>
CFireConnection<T, piid>::~CFireConnection(void)
{
if (m_pSink)
m_pSink->Release();
if (m_pEnumConn)
m_pEnumConn->Release();
}
template <class T, const IID* piid>
BOOL CFireConnection<T, piid>::Next(void)
{
if (SUCCEEDED(*m_phr))
ASSERT_READ_PTR(m_pEnumConn);
if (SUCCEEDED(*m_phr) &&
(*m_phr = m_pEnumConn->Next(1, &m_cd, NULL)) == S_OK)
{
if (m_pSink)
{
m_pSink->Release();
m_pSink = NULL;
}
if (SUCCEEDED(*m_phr = m_cd.pUnk->QueryInterface(*piid, (void**)&m_pSink)))
ASSERT_READ_PTR(m_pSink);
}
return SUCCEEDED(*m_phr);
}
template <class T, const IID* piid>
T* CFireConnection<T, piid>::Sink(void)
{
return m_pSink;
}
#endif //__UTIL_H_