Сущность технологии СОМ. Библиотека программиста - Страница 115

Изменить размер шрифта:

ModuleLock();

return InterlockedIncrement(&m_cRef);

}

STDMETHODIMP_(ULONG)

ChatSession::Release(void)

{

LONG res = InterlockedDecrement(&m_cRef);

if (res == 0)

delete this;

ModuleUnlock();

return res;

}

// IChatSession methods

STDMETHODIMP

ChatSession::get_SessionName(OLECHAR **ppwsz)

{

if (!ppwsz)

return E_INVALIDARG;

else if ((*ppwsz = OLESTRDUP(m_wszSessionName)) == 0)

return E_OUTOFMEMORY;

return S_OK;

}

STDMETHODIMP

ChatSession::Say(const OLECHAR *pwszStatement)

{

HRESULT hr = S_OK;

// protect access to method

OLECHAR *pwszUser = GetCaller();

if (pwszUser && CheckAccess(pwszUser))

{

SLock();

try

{

wstring s = pwszUser;

s += L":";

s += pwszStatement;

m_statements.push_back(s);

}

catch(...)

{

hr = E_OUTOFMEMORY;

}

SUnlock();

if (SUCCEEDED(hr))

Fire_OnNewStatement(pwszUser, pwszStatement);

}

else

hr = E_ACCESSDENIED;

CoTaskMemFree(pwszUser);

return hr;

}

STDMETHODIMP

ChatSession::GetStatements(IEnumString **ppes)

{

if (ppes == 0)

return E_INVALIDARG;

*ppes = new StatementEnumerator(this);

if (*ppes == 0)

return E_OUTOFMEMORY;

(*ppes)->AddRef();

return S_OK;

}

STDMETHODIMP

ChatSession::Advise(IChatSessionEvents *pEventSink,

DWORD *pdwReg)

{

HRESULT hr = S_OK;

if (pEventSink == 0 || pdwReg == 0)

return E_INVALIDARG;

LISTENER *pNew = new LISTENER;

if (pNew == 0)

return E_OUTOFMEMORY;

OLECHAR *pwszUser = GetCaller();

if (pwszUser)

{

Fire_OnNewUser(pwszUser);

ALock();

pNew->pwszUser = pwszUser;

if (pNew->pItf = pEventSink)

pEventSink->AddRef();

pNew->pNext = m_pHeadListeners;

if (m_pHeadListeners)

m_pHeadListeners->pPrev = pNew;

pNew->pPrev = 0;

m_pHeadListeners = pNew;

AUnlock();

}

else

{

delete pNew;

return E_OUTOFMEMORY;

}

*pdwReg = reinterpret_cast(pNew);

return hr;

}

STDMETHODIMP

ChatSession::Unadvise(DWORD dwReg)

{

if (dwReg == 0)

return E_INVALIDARG;

HRESULT hr = S_OK;

LISTENER *pThisNode = reinterpret_cast(dwReg);

ALock();

if (pThisNode->pPrev)

pThisNode->pPrev->pNext = pThisNode->pNext;

else

m_pHeadListeners = pThisNode->pNext;

if (pThisNode->pNext)

pThisNode->pNext->pPrev = pThisNode->pPrev;

if (pThisNode->pItf)

pThisNode->pItf->Release();

OLECHAR *pwszUser = pThisNode->pwszUser;

delete pThisNode;

AUnlock();

Fire_OnUserLeft(pwszUser);

CoTaskMemFree(pwszUser);

return hr;

}

// class StatementEnumerator ///////////////////

StatementEnumerator::StatementEnumerator(ChatSession *pThis)

: m_cRef(0),

m_pThis(pThis),

m_cursor(pThis->m_statements.begin())

{

m_pThis->AddRef();

InitializeCriticalSection(&m_csLock);

}

StatementEnumerator::~StatementEnumerator(void)

{

m_pThis->Release();

DeleteCriticalSection(&m_csLock);

}

// lock helpers (note that ChatSession is locked

// simultaneously)

void

StatementEnumerator::Lock(void)

{

EnterCriticalSection(&m_csLock);

m_pThis->SLock();

}

void

StatementEnumerator::Unlock(void)

{

LeaveCriticalSection(&m_csLock);

m_pThis->SUnlock();

}

// IUnknown methods

STDMETHODIMP

StatementEnumerator::QueryInterface(REFIID riid, void **ppv)

{

if (riid == IID_IUnknown)

*ppv = static_cast(this);

else if (riid == IID_IEnumString)

*ppv = static_cast(this);

else

return (*ppv = 0), E_NOINTERFACE;

reinterpret_cast(*ppv)->AddRef();

return S_OK;

}

STDMETHODIMP_(ULONG)

StatementEnumerator::AddRef(void)

{

return InterlockedIncrement(&m_cRef);

}

STDMETHODIMP_(ULONG)

StatementEnumerator::Release(void)

{

LONG res = InterlockedDecrement(&m_cRef);

if (res == 0)

delete this;

return res;

}

// IEnumString methods

STDMETHODIMP

StatementEnumerator::Next(ULONG cElems, OLECHAR **rgElems,

ULONG *pcFetched)

{

if (pcFetched == 0 && cElems > 1)

return E_INVALIDARG;

ZeroMemory(rgElems, sizeof(OLECHAR*) * cElems);

Lock();

ULONG cActual = 0;

while (cActual < cElems

&& m_cursor != m_pThis->m_statements.end())

{

if (rgElems[cActual] = OLESTRDUP((*m_cursor).c_str()))

{

m_cursor++;

cActual++;

}

else // allocation error, unwind

{

while (cActual > 0)

{

cActual–;

CoTaskMemFree(rgElems[cActual]);

rgElems[cActual] = 0;

}

break;

}

}

Unlock();

if (pcFetched)

*pcFetched = cActual;

return cElems == cActual ? S_OK : S_FALSE;

}

STDMETHODIMP

StatementEnumerator::Skip(ULONG cElems)

{

Lock();

ULONG cActual = 0;

while (cActual < cElems

&& m_cursor != m_pThis->m_statements.end())

{

m_cursor++;

cActual++;

}

Unlock();

return cElems == cActual ? S_OK : S_FALSE;

}

STDMETHODIMP

StatementEnumerator::Reset(void)

{

Lock();

m_cursor = m_pThis->m_statements.begin();

Unlock();

return S_OK;

}

STDMETHODIMP

StatementEnumerator::Clone(IEnumString **ppes)

{

if (ppes == 0)

return E_INVALIDARG;

if (*ppes = new StatementEnumerator(m_pThis))

return S_OK;

return E_OUTOFMEMORY;

}

// class ChatSessionClass /////////////////////

ChatSessionClass::ChatSessionClass(void)

: m_cStrongLocks(0)

{

InitializeCriticalSection(&m_csSessionLock);

}

ChatSessionClass::~ChatSessionClass(void)

{

DeleteCriticalSection(&m_csSessionLock);

}

void

ChatSessionClass::Lock(void)

{

EnterCriticalSection(&m_csSessionLock);

}

void

ChatSessionClass::Unlock(void)

{

LeaveCriticalSection(&m_csSessionLock);

}

// helper method to protect access to DeleteSession

// to only allow COMChat Admins to delete groups

bool

ChatSessionClass::CheckAccess(const OLECHAR *pwszUser)

{

if (wcscmp(pwszUser, L"anonymous") == 0)

return false;

TRUSTEEW trustee = {

0, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME,

TRUSTEE_IS_USER, const_cast(pwszUser)

};

BOOL bIsAllowed;

HRESULT hr = g_pacAdmins->IsAccessAllowed(&trustee,0,

COM_RIGHTS_EXECUTE,

&bIsAllowed);

if (FAILED(hr))

bIsAllowed = false;

return SUCCEEDED(hr) && bIsAllowed != FALSE;

}

// IUnknown methods

STDMETHODIMP

ChatSessionClass::QueryInterface(REFIID riid, void **ppv)

{

if (riid == IID_IUnknown)

*ppv = static_cast(this);

else if (riid == IID_IChatSessionManager)

*ppv = static_cast(this);

else if (riid == IID_IExternalConnection)

*ppv = static_cast(this);

else

return (*ppv = 0), E_NOINTERFACE;

reinterpret_cast(*ppv)->AddRef();

return S_OK;

}

STDMETHODIMP_(ULONG)

Оригинальный текст книги читать онлайн бесплатно в онлайн-библиотеке Knigger.com