CLUTIL.CPP
//**************************************************************************** 
//  Module:     NMFT.EXE 
//  File:       CLUTIL.CPP 
//  Content:     
//               
// 
//  Copyright (c) Microsoft Corporation 1997 
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF  
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO  
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A  
// PARTICULAR PURPOSE. 
//**************************************************************************** 
 
 
#include "precomp.h" 
 
//**************************************************************************** 
// 
// CLASS RefCount 
// 
//**************************************************************************** 
 
 
//**************************************************************************** 
// 
// Constructor 
// 
//**************************************************************************** 
 
RefCount::RefCount(void) 
{ 
m_cRef = 1; 
} 
 
 
//**************************************************************************** 
// 
// Destructor 
// 
//**************************************************************************** 
 
RefCount::~RefCount(void) 
{ 
} 
 
 
//**************************************************************************** 
// 
// Methods from IUnknown 
// 
//**************************************************************************** 
 
ULONG STDMETHODCALLTYPE RefCount::AddRef(void) 
{ 
   ASSERT(m_cRef >= 0); 
 
   InterlockedIncrement(&m_cRef); 
 
   return (ULONG) m_cRef; 
} 
 
 
ULONG STDMETHODCALLTYPE RefCount::Release(void) 
{ 
if (0 == InterlockedDecrement(&m_cRef)) 
{ 
delete this; 
return 0; 
} 
 
ASSERT(m_cRef > 0); 
return (ULONG) m_cRef; 
} 
 
 
//**************************************************************************** 
// 
// CLASS CNotify 
// 
//**************************************************************************** 
 
 
//**************************************************************************** 
// 
// Constructor 
// 
//**************************************************************************** 
 
CNotify::CNotify() : 
m_pcnpcnt(NULL), 
    m_pcnp(NULL), 
    m_dwCookie(0), 
    m_pUnk(NULL) 
{ 
} 
 
 
//**************************************************************************** 
// 
// Destructor 
// 
//**************************************************************************** 
 
CNotify::~CNotify() 
{ 
Disconnect(); // Make sure we're disconnected 
} 
 
 
//**************************************************************************** 
// 
// HRESULT CNotify::Connect(IUnknown *pUnk, REFIID riid, IUnknown *pUnkN) 
// 
//**************************************************************************** 
 
HRESULT CNotify::Connect(IUnknown *pUnk, REFIID riid, IUnknown *pUnkN) 
{ 
HRESULT hr; 
 
ASSERT(0 == m_dwCookie); 
 
// Get the connection container 
hr = pUnk->QueryInterface(IID_IConnectionPointContainer, (void **)&m_pcnpcnt); 
if (SUCCEEDED(hr)) 
{ 
// Find an appropriate connection point 
hr = m_pcnpcnt->FindConnectionPoint(riid, &m_pcnp); 
if (SUCCEEDED(hr)) 
{ 
ASSERT(NULL != m_pcnp); 
// Connect the sink object 
hr = m_pcnp->Advise((IUnknown *)pUnkN, &m_dwCookie); 
} 
} 
 
if (FAILED(hr)) 
{ 
m_dwCookie = 0; 
} 
else 
{ 
    m_pUnk = pUnk; // keep around for caller 
    } 
 
return hr; 
} 
 
 
//**************************************************************************** 
// 
// HRESULT CNotify::Disconnect (void) 
// 
//**************************************************************************** 
 
HRESULT CNotify::Disconnect (void) 
{ 
    if (0 != m_dwCookie) 
    { 
        // Disconnect the sink object 
        m_pcnp->Unadvise(m_dwCookie); 
        m_dwCookie = 0; 
 
        m_pcnp->Release(); 
        m_pcnp = NULL; 
 
        m_pcnpcnt->Release(); 
        m_pcnpcnt = NULL; 
 
        m_pUnk = NULL; 
    } 
 
    return S_OK; 
} 
 
 
//**************************************************************************** 
// 
// CLASS COBLIST 
// 
//**************************************************************************** 
 
 
//**************************************************************************** 
// 
// Destructor 
// 
//**************************************************************************** 
 
COBLIST::~COBLIST() 
{ 
    ASSERT(IsEmpty()); 
} 
 
 
#ifdef DEBUG 
VOID* COBLIST::GetHead() 
{ 
ASSERT(m_pHead); 
 
return m_pHead->pItem; 
} 
    
VOID* COBLIST::GetTail() 
{ 
ASSERT(m_pTail); 
 
return m_pTail->pItem; 
} 
#endif /* DEBUG */ 
 
 
//**************************************************************************** 
// 
// VOID* COBLIST::GetNext(POSITION& rPos) 
// 
//**************************************************************************** 
 
VOID* COBLIST::GetNext(POSITION& rPos) 
{ 
ASSERT(rPos); 
 
VOID* pReturn = rPos->pItem; 
rPos = rPos->pNext; 
 
return pReturn; 
} 
 
 
//**************************************************************************** 
// 
// VOID* COBLIST::RemoveAt(POSITION Pos) 
// 
//**************************************************************************** 
 
VOID* COBLIST::RemoveAt(POSITION Pos) 
{ 
VOID* pReturn = NULL; 
 
if (m_pHead) 
{ 
if (m_pHead == Pos) 
{ 
// Removing the first element in the list 
 
m_pHead = Pos->pNext; 
pReturn = Pos->pItem; 
delete Pos; 
m_cItem--; 
ASSERT(0 <= m_cItem); 
 
if (NULL == m_pHead) 
{ 
// Removing the only element! 
m_pTail = NULL; 
} 
} 
else 
{ 
POSITION pCur = m_pHead; 
 
while (pCur && pCur->pNext) 
{ 
if (pCur->pNext == Pos) 
{ 
// Removing  
 
pCur->pNext = Pos->pNext; 
if (m_pTail == Pos) 
{ 
m_pTail = pCur; 
} 
pReturn = Pos->pItem; 
delete Pos; 
 
m_cItem--; 
ASSERT(0 <= m_cItem); 
} 
 
pCur = pCur->pNext; 
} 
} 
} 
 
return pReturn; 
} 
 
 
//**************************************************************************** 
// 
// POSITION COBLIST::AddTail(VOID* pItem) 
// 
//**************************************************************************** 
 
POSITION COBLIST::AddTail(VOID* pItem) 
{ 
POSITION posRet = NULL; 
 
if (m_pTail) 
{ 
if (m_pTail->pNext = new COBNODE) 
{ 
m_pTail = m_pTail->pNext; 
m_pTail->pItem = pItem; 
m_pTail->pNext = NULL; 
m_cItem++; 
} 
} 
else 
{ 
ASSERT(!m_pHead); 
if (m_pHead = new COBNODE) 
{ 
m_pTail = m_pHead; 
m_pTail->pItem = pItem; 
m_pTail->pNext = NULL; 
m_cItem++; 
} 
} 
 
return m_pTail; 
} 
 
 
//**************************************************************************** 
// 
// void COBLIST::EmptyList() 
// 
//**************************************************************************** 
 
void COBLIST::EmptyList() 
{ 
    while (!IsEmpty()) { 
        RemoveAt(GetHeadPosition()); 
    } 
} 
 
 
#ifdef DEBUG 
VOID* COBLIST::RemoveTail() 
{ 
ASSERT(m_pHead); 
ASSERT(m_pTail); 
 
return RemoveAt(m_pTail); 
} 
 
VOID* COBLIST::RemoveHead() 
{ 
ASSERT(m_pHead); 
ASSERT(m_pTail); 
 
return RemoveAt(m_pHead); 
} 
 
void * COBLIST::GetFromPosition(POSITION Pos) 
{ 
    void * Result = SafeGetFromPosition(Pos); 
ASSERT(Result); 
return Result; 
} 
#endif /* DEBUG */ 
 
 
//**************************************************************************** 
// 
// POSITION COBLIST::GetPosition(void* _pItem) 
// 
//**************************************************************************** 
 
POSITION COBLIST::GetPosition(void* _pItem) 
{ 
    POSITION    Position = m_pHead; 
 
    while (Position) { 
        if (Position->pItem == _pItem) { 
            break; 
        } 
GetNext(Position); 
    } 
    return Position; 
} 
 
 
//**************************************************************************** 
// 
// POSITION COBLIST::Lookup(void* pComparator) 
// 
//**************************************************************************** 
 
POSITION COBLIST::Lookup(void* pComparator) 
{ 
    POSITION    Position = m_pHead; 
 
    while (Position) { 
        if (Compare(Position->pItem, pComparator)) { 
            break; 
        } 
GetNext(Position); 
    } 
    return Position; 
} 
 
 
//**************************************************************************** 
// 
// void * COBLIST::SafeGetFromPosition(POSITION Pos) 
// 
//**************************************************************************** 
 
void * COBLIST::SafeGetFromPosition(POSITION Pos) 
{ 
// Safe way to validate that an entry is still in the list, 
// which ensures bugs that would reference deleted memory, 
// reference a NULL pointer instead 
// (e.g. an event handler fires late/twice). 
// Note that versioning on entries would provide an additional  
// safeguard against re-use of a position. 
// Walklist to find entry. 
 
POSITION PosWork = m_pHead; 
 
while (PosWork) { 
if (PosWork == Pos) { 
return Pos->pItem; 
} 
GetNext(PosWork); 
} 
return NULL; 
} 
 
//**************************************************************************** 
// 
// COBLIST Utility routines 
// 
//**************************************************************************** 
 
 
//**************************************************************************** 
// 
// POSITION AddNode(PVOID pv, COBLIST ** ppList) 
// 
// Add a node to a list. 
// Initializes the ObList, if necessary. 
// Returns the position in the list or NULL if there was a problem. 
// 
//**************************************************************************** 
 
POSITION AddNode(PVOID pv, COBLIST ** ppList) 
{ 
ASSERT(NULL != ppList); 
if (NULL == *ppList) 
{ 
*ppList = new COBLIST(); 
if (NULL == *ppList) 
return NULL; 
} 
 
return (*ppList)->AddTail(pv); 
} 
 
 
//**************************************************************************** 
// 
// PVOID RemoveNode(POSITION * pPos, COBLIST *pList) 
// 
// Remove a node from a list. 
// Sets pPos to NULL 
// 
//**************************************************************************** 
 
PVOID RemoveNode(POSITION * pPos, COBLIST *pList) 
{ 
if ((NULL == pList) || (NULL == pPos)) 
return NULL; 
 
PVOID pv = pList->RemoveAt(*pPos); 
*pPos = NULL; 
return pv; 
} 
 
 
//**************************************************************************** 
// 
// CLASS BSTRING 
// 
//**************************************************************************** 
 
 
//**************************************************************************** 
// 
// Constructor 
// 
// We don't support construction from an ANSI string in the Unicode build. 
// 
//**************************************************************************** 
 
#if !defined(UNICODE) 
 
BSTRING::BSTRING(LPCSTR lpcString) 
{ 
m_bstr = NULL; 
 
// Compute the length of the required BSTR, including the null 
int cWC =  MultiByteToWideChar(CP_ACP, 0, lpcString, -1, NULL, 0); 
if (cWC <= 0) 
return; 
 
// Allocate the BSTR, including the null 
m_bstr = SysAllocStringLen(NULL, cWC - 1); // SysAllocStringLen adds another 1 
 
ASSERT(NULL != m_bstr); 
if (NULL == m_bstr) 
{ 
return; 
} 
 
// Copy the string 
MultiByteToWideChar(CP_ACP, 0, lpcString, -1, (LPWSTR) m_bstr, cWC); 
 
// Verify that the string is null terminated 
ASSERT(0 == m_bstr[cWC - 1]); 
} 
 
#endif // !defined(UNICODE) 
 
 
//**************************************************************************** 
// 
// CLASS BTSTR 
// 
//**************************************************************************** 
 
//**************************************************************************** 
// 
// Constructor 
// 
//**************************************************************************** 
 
BTSTR::BTSTR(BSTR bstr) 
{ 
m_psz = PszFromBstr(bstr); 
} 
 
 
//**************************************************************************** 
// 
// Destructor 
// 
//**************************************************************************** 
 
BTSTR::~BTSTR() 
{ 
if (NULL != m_psz) 
LocalFree(m_psz); 
} 
 
 
//**************************************************************************** 
// 
// LPTSTR PszFromBstr(BSTR bstr) 
// 
// Converts a BSTR to a LPSTR 
// 
//**************************************************************************** 
 
LPTSTR PszFromBstr(BSTR bstr) 
{ 
if (NULL == bstr) 
return NULL; 
int cch =  WideCharToMultiByte(CP_ACP, 0, (LPWSTR)bstr, -1, NULL, 0, NULL, NULL); 
if (cch <= 0) 
return NULL; 
 
LPTSTR psz = PszAlloc(cch); 
if (NULL == psz) 
return NULL; 
 
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)bstr, -1, psz, cch+1, NULL, NULL); 
return psz; 
}