You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
563 lines
13 KiB
C++
563 lines
13 KiB
C++
// XTPNotifyConnection.cpp: implementation of the CXTPNotifyConnection and CXTPNotifySink classes.
|
|
//
|
|
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "XTPNotifyConnection.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#pragma warning(disable: 4571) // warning C4571: catch(...) blocks compiled with /EHs do not catch or re-throw Structured Exceptions
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
static LPCTSTR XTP_NOTIFICATION_SINK_MT_MSGWND_NAME = _T("XTPNotificationSinkMT_MsgWnd");
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//class CEmptySyncObject : public CSyncObject
|
|
|
|
CXTPNotifyConnection::CEmptySyncObject::CEmptySyncObject() :
|
|
CSyncObject(_T("XTPEmptySyncObject"))
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
CXTPNotifyConnection::CXTPNotifyConnection()
|
|
{
|
|
m_nSendQueueCacheSize = 0;
|
|
}
|
|
|
|
CXTPNotifyConnection::~CXTPNotifyConnection()
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
void CXTPNotifyConnection::RemoveAll()
|
|
{
|
|
CSingleLock singleLock(GetDataLock(), TRUE);
|
|
|
|
int nCount = (int)m_arrConnections.GetSize();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
CONNECTION_DESCRIPTOR* pCurElem = m_arrConnections[i];
|
|
ASSERT(pCurElem);
|
|
if (pCurElem)
|
|
{
|
|
delete pCurElem;
|
|
}
|
|
m_arrConnections[i] = NULL;
|
|
}
|
|
|
|
m_arrConnections.RemoveAll();
|
|
}
|
|
|
|
XTP_CONNECTION_ID CXTPNotifyConnection::Advise(XTP_NOTIFY_CODE Event, CXTPNotifySinkBase* pSink)
|
|
{
|
|
ASSERT(pSink);
|
|
|
|
CSingleLock singleLock(GetDataLock(), TRUE);
|
|
|
|
CONNECTION_DESCRIPTOR* pNewElem = new CONNECTION_DESCRIPTOR;
|
|
|
|
if (!pNewElem)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pNewElem->dwConnectionID = (XTP_CONNECTION_ID)pNewElem;
|
|
pNewElem->dwNotifyCode = Event;
|
|
pNewElem->pSink = pSink;
|
|
|
|
m_arrConnections.Add(pNewElem);
|
|
|
|
return pNewElem->dwConnectionID;
|
|
}
|
|
|
|
void CXTPNotifyConnection::Unadvise(XTP_CONNECTION_ID ConnectionID)
|
|
{
|
|
CSingleLock singleLock(GetDataLock(), TRUE);
|
|
|
|
try
|
|
{
|
|
int nCount = (int)m_arrConnections.GetSize();
|
|
int nFIndex = FindConnection(ConnectionID);
|
|
|
|
if (nFIndex >= 0 && nFIndex < nCount)
|
|
{
|
|
CONNECTION_DESCRIPTOR* pElem = m_arrConnections[nFIndex];
|
|
|
|
ASSERT(pElem);
|
|
if (pElem)
|
|
{
|
|
delete pElem;
|
|
}
|
|
m_arrConnections.RemoveAt(nFIndex);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
ASSERT(FALSE);
|
|
TRACE(_T("EXCEPTION! CXTPNotifyConnection::Unadvise(ConnectionID = %d)\n"), ConnectionID);
|
|
}
|
|
}
|
|
|
|
BOOL CXTPNotifyConnection::SendEvent(XTP_NOTIFY_CODE Event,
|
|
WPARAM wParam , LPARAM lParam, DWORD dwFlags)
|
|
{
|
|
CSingleLock singleLock(GetDataLock(), TRUE);
|
|
InternalAddRef();
|
|
|
|
int nCount = (int)m_arrConnections.GetSize();
|
|
|
|
if (m_arrSendQueueCache.GetSize() < nCount + m_nSendQueueCacheSize)
|
|
{
|
|
m_arrSendQueueCache.SetSize(nCount + m_nSendQueueCacheSize);
|
|
}
|
|
//******************************************************************************
|
|
int nFirstLocalClientIndex = m_nSendQueueCacheSize;
|
|
|
|
int i;
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
CONNECTION_DESCRIPTOR* pElem = m_arrConnections[i];
|
|
ASSERT(pElem);
|
|
if (pElem && pElem->dwNotifyCode == Event)
|
|
{
|
|
m_arrSendQueueCache.SetAt(m_nSendQueueCacheSize, *pElem);
|
|
m_nSendQueueCacheSize++;
|
|
}
|
|
}
|
|
int nLastLocalClientIndex = m_nSendQueueCacheSize-1;
|
|
|
|
singleLock.Unlock();
|
|
//************************************************************************
|
|
for (i = nFirstLocalClientIndex; i <= nLastLocalClientIndex; i++)
|
|
{
|
|
singleLock.Lock();
|
|
|
|
if (i >= m_arrSendQueueCache.GetSize())
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
CONNECTION_DESCRIPTOR& rElem = m_arrSendQueueCache.ElementAt(i);
|
|
int nFIndex = FindConnection(rElem.dwConnectionID);
|
|
if (nFIndex < 0)
|
|
{
|
|
// Unadvise was called inside OnEvent(...) Call
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
CXTPNotifySinkBase* ptrSink = rElem.pSink;
|
|
|
|
singleLock.Unlock();
|
|
|
|
if (ptrSink)
|
|
{
|
|
ptrSink->OnEvent(Event, wParam, lParam, dwFlags);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
TRACE(_T("CXTPNotifyConnection::SendEvent(Event = %d, wParam = %d, lParam = %d, dwFlags = %x) pSink = %x\n"),
|
|
Event, wParam, lParam, dwFlags, rElem.pSink);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
ASSERT(FALSE);
|
|
TRACE(_T("EXCEPTION! CXTPNotifyConnection::SendEvent(Event = %d, wParam = %d, lParam = %d, dwFlags = %x)\n"),
|
|
Event, wParam, lParam, dwFlags);
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
singleLock.Lock();
|
|
|
|
m_nSendQueueCacheSize = nFirstLocalClientIndex;
|
|
|
|
singleLock.Unlock();
|
|
|
|
InternalRelease();
|
|
return (nFirstLocalClientIndex <= nLastLocalClientIndex);
|
|
}
|
|
|
|
int CXTPNotifyConnection::FindConnection(XTP_CONNECTION_ID ConnectionID)
|
|
{
|
|
CSingleLock singleLock(GetDataLock(), TRUE);
|
|
|
|
int nCount = (int)m_arrConnections.GetSize();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
CONNECTION_DESCRIPTOR* pCurElem = m_arrConnections[i];
|
|
ASSERT(pCurElem);
|
|
if (pCurElem)
|
|
{
|
|
if (pCurElem->dwConnectionID == ConnectionID)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//class CXTPNotifyConnectionMT : public CXTPNotifyConnection
|
|
|
|
CXTPNotifyConnectionMT::CXTPNotifyConnectionMT()
|
|
{
|
|
}
|
|
|
|
CXTPNotifyConnectionMT::~CXTPNotifyConnectionMT()
|
|
{
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
BEGIN_MESSAGE_MAP(CXTPNotifySinkImplMTMsgWnd, CWnd)
|
|
ON_REGISTERED_MESSAGE(xtp_wm_NotificationSinkMTOnEvent, HandleInterThreadEvent)
|
|
END_MESSAGE_MAP()
|
|
|
|
CXTPNotifySinkImplMTMsgWnd::CXTPNotifySinkImplMTMsgWnd()
|
|
{
|
|
}
|
|
|
|
CXTPNotifySinkImplMTMsgWnd::~CXTPNotifySinkImplMTMsgWnd()
|
|
{
|
|
}
|
|
|
|
LRESULT CXTPNotifySinkImplMTMsgWnd::HandleInterThreadEvent(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return OnInterThreadEvent(wParam, lParam);
|
|
}
|
|
|
|
BOOL CXTPNotifySinkImplMTMsgWnd::CreateWnd()
|
|
{
|
|
LPCTSTR pcszSimpleWndClass = AfxRegisterWndClass(0);
|
|
CRect rcEmpty(0, 0, 0, 0);
|
|
|
|
BOOL bCreated = CreateEx(0, pcszSimpleWndClass,
|
|
XTP_NOTIFICATION_SINK_MT_MSGWND_NAME,
|
|
WS_POPUP, rcEmpty, NULL, 0);
|
|
ASSERT(bCreated);
|
|
return bCreated;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CXTPNotifySinkBase
|
|
|
|
CXTPNotifySinkBase::CXTPNotifySinkBase()
|
|
{
|
|
}
|
|
|
|
CXTPNotifySinkBase::~CXTPNotifySinkBase()
|
|
{
|
|
// Should call UnadviseAll before delete
|
|
ASSERT(m_mapAdviseData.IsEmpty());
|
|
}
|
|
|
|
XTP_CONNECTION_ID CXTPNotifySinkBase::Advise(CXTPNotifyConnection* pConnection,
|
|
XTP_NOTIFY_CODE dwNotifyCode)
|
|
{
|
|
ASSERT(pConnection);
|
|
if (!pConnection)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
XTP_CONNECTION_ID dwConnectionID = pConnection->Advise(dwNotifyCode, this);
|
|
ASSERT(dwConnectionID);
|
|
|
|
if (dwConnectionID)
|
|
{
|
|
ADVISE_DESCRIPTOR advDataNew;
|
|
ASSERT(!m_mapAdviseData.Lookup(dwConnectionID, advDataNew));
|
|
|
|
advDataNew.dwConnectionID = dwConnectionID;
|
|
advDataNew.pConnection = pConnection;
|
|
advDataNew.dwNotifyCode = dwNotifyCode;
|
|
pConnection->InternalAddRef();
|
|
|
|
m_mapAdviseData.SetAt(dwConnectionID, advDataNew);
|
|
|
|
}
|
|
return dwConnectionID;
|
|
}
|
|
|
|
void CXTPNotifySinkBase::UnadviseAll()
|
|
{
|
|
XTP_CONNECTION_ID ConnectionID = 0;
|
|
ADVISE_DESCRIPTOR advData;
|
|
POSITION pos = m_mapAdviseData.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
m_mapAdviseData.GetNextAssoc(pos, ConnectionID, advData);
|
|
if (advData.pConnection)
|
|
{
|
|
OnUnadvise(advData.dwNotifyCode);
|
|
|
|
advData.pConnection->Unadvise(advData.dwConnectionID);
|
|
advData.pConnection->InternalRelease();
|
|
}
|
|
}
|
|
m_mapAdviseData.RemoveAll();
|
|
}
|
|
|
|
void CXTPNotifySinkBase::Unadvise(XTP_CONNECTION_ID ConnectionID)
|
|
{
|
|
ADVISE_DESCRIPTOR advData;
|
|
if (m_mapAdviseData.Lookup(ConnectionID, advData))
|
|
{
|
|
if (advData.pConnection)
|
|
{
|
|
OnUnadvise(advData.dwNotifyCode);
|
|
|
|
advData.pConnection->Unadvise(advData.dwConnectionID);
|
|
advData.pConnection->InternalRelease();
|
|
}
|
|
m_mapAdviseData.RemoveKey(ConnectionID);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
void CXTPNotifySinkBase::OnUnadvise(XTP_NOTIFY_CODE /*dwNotifyCode*/)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CXTPNotifySink
|
|
|
|
|
|
CXTPNotifySink::CXTPNotifySink()
|
|
{
|
|
m_mapHandlers.InitHashTable(10, FALSE);
|
|
}
|
|
|
|
CXTPNotifySink::~CXTPNotifySink()
|
|
{
|
|
ASSERT(m_mapHandlers.IsEmpty());
|
|
}
|
|
|
|
void CXTPNotifySink::OnUnadvise(XTP_NOTIFY_CODE dwNotifyCode)
|
|
{
|
|
CXTPNotifySinkDelegate* pOldDelegate = NULL;
|
|
|
|
if (m_mapHandlers.Lookup(dwNotifyCode, pOldDelegate))
|
|
{
|
|
delete pOldDelegate;
|
|
m_mapHandlers.RemoveKey(dwNotifyCode);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
XTP_CONNECTION_ID CXTPNotifySink::Advise(CXTPNotifyConnection* pConnection, XTP_NOTIFY_CODE dwNotifyCode, CXTPNotifySinkDelegate* pDelegate)
|
|
{
|
|
CXTPNotifySinkDelegate* pOldDelegate = NULL;
|
|
|
|
if (m_mapHandlers.Lookup(dwNotifyCode, pOldDelegate))
|
|
{
|
|
ASSERT(FALSE);
|
|
delete pOldDelegate;
|
|
}
|
|
|
|
m_mapHandlers[dwNotifyCode] = pDelegate;
|
|
|
|
return CXTPNotifySinkBase::Advise(pConnection, dwNotifyCode);
|
|
}
|
|
|
|
void CXTPNotifySink::OnEvent(XTP_NOTIFY_CODE dwNotifyCode, WPARAM wParam, LPARAM lParam, DWORD /*dwFlags*/)
|
|
{
|
|
CXTPNotifySinkDelegate* pDelegate = NULL;
|
|
if (m_mapHandlers.Lookup(dwNotifyCode, pDelegate) && (pDelegate != NULL))
|
|
{
|
|
pDelegate->OnEvent(dwNotifyCode, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
//WARNING. no handler found. ???
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
void CXTPNotifySink::Delete()
|
|
{
|
|
UnadviseAll();
|
|
delete this;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CXTPNotifySinkMT
|
|
|
|
|
|
|
|
CXTPNotifySinkMT::CXTPNotifySinkMT(BOOL bInitInternal /*= TRUE*/)
|
|
{
|
|
m_dwTraceFlag0 = 0;
|
|
m_dwNexDataID = 0;
|
|
m_bWndCreated = FALSE;
|
|
m_dwOwnerThreadID = ::GetCurrentThreadId();
|
|
|
|
if (bInitInternal)
|
|
{
|
|
m_bWndCreated = CreateWnd();
|
|
}
|
|
|
|
m_PostedEvents.InitHashTable(199, FALSE);
|
|
}
|
|
|
|
CXTPNotifySinkMT::~CXTPNotifySinkMT()
|
|
{
|
|
UnadviseAll();
|
|
|
|
DestroyWindow();
|
|
m_bWndCreated = FALSE;
|
|
}
|
|
|
|
void CXTPNotifySinkMT::OnEvent(XTP_NOTIFY_CODE dwNotifyCode, WPARAM wParam, LPARAM lParam, DWORD dwFlags)
|
|
{
|
|
ASSERT(m_bWndCreated);
|
|
|
|
if (dwFlags & xtpNotifyDirectCallForOneThread)
|
|
{
|
|
if (GetCurrentThreadId() == m_dwOwnerThreadID)
|
|
{
|
|
CXTPNotifySink::OnEvent(dwNotifyCode, wParam, lParam, dwFlags);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//====================================================================
|
|
XTP_INTER_THREAD_EVENT_DATA ithData = {dwNotifyCode, wParam, lParam, dwFlags};
|
|
|
|
if (dwFlags & xtpNotifyPostMessage)
|
|
{
|
|
CSingleLock singleLock(&m_DataCS, TRUE);
|
|
|
|
#ifdef _DEBUG
|
|
XTP_INTER_THREAD_EVENT_DATA ithDataTmp;
|
|
ASSERT(m_PostedEvents.Lookup(m_dwNexDataID, ithDataTmp) == FALSE);
|
|
#endif
|
|
|
|
DWORD dwDataID = m_dwNexDataID;
|
|
m_dwNexDataID++;
|
|
|
|
|
|
BOOL bTrace1 = FALSE;
|
|
BOOL bPosted = FALSE;
|
|
do
|
|
{
|
|
bPosted = PostMessage(xtp_wm_NotificationSinkMTOnEvent, NULL, dwDataID);
|
|
if (!bPosted && (dwFlags & xtpNotifyGuarantyPost))
|
|
{
|
|
if (!bTrace1) {
|
|
TRACE(_T("WARNING! CXTPNotifySinkBaseImplMT: PostMessage return FALSE. WAIT and retry. (ThreadID = %x, dataID = %d) \n"),
|
|
GetCurrentThreadId(), dwDataID);
|
|
bTrace1 = TRUE;
|
|
}
|
|
|
|
singleLock.Unlock();
|
|
Sleep(100);
|
|
singleLock.Lock();
|
|
}
|
|
}
|
|
while (!bPosted && (dwFlags & xtpNotifyGuarantyPost));
|
|
|
|
if (bPosted)
|
|
{
|
|
m_PostedEvents[dwDataID] = ithData;
|
|
|
|
if (bTrace1) {
|
|
TRACE(_T("WARNING.* CXTPNotifySinkBaseImplMT: Event is posted! (ThreadID = %x, dataID = %d) \n"),
|
|
GetCurrentThreadId(), dwDataID);
|
|
}
|
|
|
|
m_dwTraceFlag0 = 0;
|
|
}
|
|
else if (!(dwFlags & xtpNotifyGuarantyPost))
|
|
{
|
|
if (m_dwTraceFlag0 < 3)
|
|
{
|
|
TRACE(_T("WARNING! CXTPNotifySinkBaseImplMT: PostMessage return FALSE - Event is skipped! (ThreadID = %x, dataID = %d) \n"),
|
|
GetCurrentThreadId(), dwDataID);
|
|
TRACE(_T(" Use xtpNotifyGuarantyPost flag for important events. \n"));
|
|
}
|
|
m_dwTraceFlag0++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendMessage(xtp_wm_NotificationSinkMTOnEvent, (WPARAM)&ithData, 0);
|
|
}
|
|
};
|
|
|
|
LRESULT CXTPNotifySinkMT::OnInterThreadEvent(WPARAM pEventData, LPARAM dwPostDataID)
|
|
{
|
|
XTP_INTER_THREAD_EVENT_DATA* pIthData = (XTP_INTER_THREAD_EVENT_DATA*)pEventData;
|
|
|
|
if (pIthData)
|
|
{
|
|
CXTPNotifySink::OnEvent(pIthData->dwNotifyCode, pIthData->wParam,
|
|
pIthData->lParam, pIthData->dwFlags);
|
|
}
|
|
else
|
|
{
|
|
XTP_INTER_THREAD_EVENT_DATA ithData;
|
|
|
|
CSingleLock singleLock(&m_DataCS, TRUE);
|
|
|
|
if (m_PostedEvents.Lookup((DWORD)dwPostDataID, ithData))
|
|
{
|
|
m_PostedEvents.RemoveKey((DWORD)dwPostDataID);
|
|
|
|
singleLock.Unlock();
|
|
|
|
CXTPNotifySink::OnEvent(ithData.dwNotifyCode, ithData.wParam,
|
|
ithData.lParam, ithData.dwFlags);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
//====================================================================
|
|
return 0;
|
|
};
|