#include "stdafx.h" #include "IPCChannel.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /////////////////////////////////////////////////////////////////////////////// // CSharedBlob class CSharedBlob { public: explicit CSharedBlob(UINT id); CSharedBlob(const void* pData, SIZE_T cbSize); ~CSharedBlob() { Close(); } BOOL IsOpen() const { return NULL != m_pData; } UINT GetID() const { return m_nID; } LPVOID GetData() const { return m_pData; } SIZE_T GetSize() const { return m_cbSize; } private: void Close(); static CString MakeName(UINT id); HANDLE m_hFile; UINT m_nID; LPVOID m_pData; SIZE_T m_cbSize; }; CSharedBlob::CSharedBlob(UINT id) : m_hFile(NULL) , m_nID(id) , m_pData(NULL) , m_cbSize(0) { CString strName = MakeName(id); m_hFile = ::OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, strName); if (NULL != m_hFile) { SIZE_T* pSize = reinterpret_cast( ::MapViewOfFile(m_hFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0)); if (NULL != pSize) { m_cbSize = *pSize; m_pData = pSize + 1; } } if (!IsOpen()) { Close(); } } CSharedBlob::CSharedBlob(const void* pData, SIZE_T cbSize) : m_hFile(NULL) , m_nID(0) , m_pData(NULL) , m_cbSize(0) { _ASSERTE(NULL != pData); _ASSERTE(0 < cbSize); m_nID = GetTickCount(); CString strName = MakeName(m_nID); ULARGE_INTEGER cbLSize; cbLSize.QuadPart = cbSize; m_hFile = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, cbLSize.HighPart, cbLSize.LowPart, strName); if (NULL != m_hFile) { SIZE_T* pSize = reinterpret_cast(::MapViewOfFile(m_hFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(SIZE_T) + cbSize)); if (NULL != pSize) { *pSize = cbSize; m_cbSize = cbSize; m_pData = pSize + 1; memcpy(m_pData, pData, m_cbSize); } } if (!IsOpen()) { Close(); } } void CSharedBlob::Close() { if (NULL != m_pData) { ::UnmapViewOfFile(reinterpret_cast(m_pData) - 1); m_pData = NULL; } if (NULL != m_hFile) { ::CloseHandle(m_hFile); m_hFile = NULL; } m_nID = 0; m_cbSize = 0; } CString CSharedBlob::MakeName(UINT id) { CString strName; strName.Format(_T("XTP_CIPCChannel_SharedBlob_%08X"), id); return strName; } /////////////////////////////////////////////////////////////////////////////// // CIPCChannel const UINT CIPCChannel::m_WM_IPC = ::RegisterWindowMessage( _T("{DC35017F-6D7B-48FA-A721-EE2C99FC2B7B}")); CIPCChannel::CIPCChannel(IIPCChannelCallback& callback) : m_type(UninitializedChannel) , m_Callback(callback) , m_pCurrentBlob(NULL) { } CIPCChannel::~CIPCChannel() { CloseChannel(); } void CIPCChannel::OpenClientChannel(HWND hwndLocal, HWND hwndRemote) { _ASSERTE(!IsOpen()); m_type = ClientChannel; m_hwndLocal = hwndLocal; m_hwndRemote = hwndRemote; ExecuteAsync(cmdClientAttached, 0, reinterpret_cast(hwndLocal)); } void CIPCChannel::OpenServerChannel(HWND hwndLocal) { _ASSERTE(!IsOpen()); m_type = ServerChannel; m_hwndLocal = hwndLocal; m_hwndRemote = NULL; } void CIPCChannel::CloseChannel() { CloseChannel(TRUE); } BOOL CIPCChannel::IsOpen() const { return UninitializedChannel != m_type; } BOOL CIPCChannel::IsServer() const { return ServerChannel == m_type; } BOOL CIPCChannel::IsClient() const { return ClientChannel == m_type; } void CIPCChannel::PostNotification(WORD wCode, LPARAM lParam /*= 0*/) { ExecuteAsync(cmdNotification, wCode, lParam); } LRESULT CIPCChannel::SendNotification(WORD wCode, LPARAM lParam /*= 0*/) { return Execute(cmdNotification, wCode, lParam); } LRESULT CIPCChannel::SendData(WORD wCode, const void* pData, SIZE_T cbSize) { LRESULT lResult = 0; CSharedBlob* pBlob = SetBlob(pData, cbSize); if (NULL != pBlob) { lResult = Execute(cmdData, wCode, pBlob->GetID()); } return lResult; } BOOL CIPCChannel::ProcessMessage(UINT nMessage, WPARAM wParam, LPARAM lParam, LRESULT& lResult) { BOOL bProcessed = FALSE; if (m_WM_IPC == nMessage) { switch (LOWORD(wParam)) { case cmdClientAttached: lResult = OnCmdClientAttached(lParam); break; case cmdClientAttachedACK: lResult = OnCmdClientAttachedACK(lParam); break; case cmdPeerDisconnected: lResult = OnCmdPeerDisconnected(lParam); break; case cmdNotification: lResult = OnCmdNotification(HIWORD(wParam), lParam); break; case cmdData: lResult = OnCmdData(HIWORD(wParam), lParam); break; default: lResult = 0; break; } bProcessed = TRUE; } return bProcessed; } BOOL CIPCChannel::IsPeerAccessible() { return NULL != m_hwndRemote && ::IsWindow(m_hwndRemote); } void CIPCChannel::CloseChannel(BOOL bNotifyRemote) { if (bNotifyRemote && IsPeerAccessible()) { Execute(cmdPeerDisconnected, 0); } ReleaseBlob(); m_hwndLocal = NULL; m_hwndRemote = NULL; m_type = UninitializedChannel; } void CIPCChannel::ExecuteAsync(IPCCommand cmd, WORD wCode, LPARAM lParam) { if (IsPeerAccessible()) { ::PostMessage(m_hwndRemote, m_WM_IPC, MAKELONG(cmd, wCode), lParam); } } LRESULT CIPCChannel::Execute(IPCCommand cmd, WORD wCode, LPARAM lParam) { LRESULT lResult = 0; if (IsPeerAccessible()) { lResult = ::SendMessage(m_hwndRemote, m_WM_IPC, MAKELONG(cmd, wCode), lParam); } return lResult; } CSharedBlob* CIPCChannel::SetBlob(const void* pData, SIZE_T cbData) { _ASSERTE(NULL != pData); _ASSERTE(0 != cbData); ReleaseBlob(); m_pCurrentBlob = new CSharedBlob(pData, cbData); if (!m_pCurrentBlob->IsOpen()) { ReleaseBlob(); TRACE(_T("Unable to create shared blob of size %i bytes\n"), cbData); } return m_pCurrentBlob; } void CIPCChannel::ReleaseBlob() { if (NULL != m_pCurrentBlob) { delete m_pCurrentBlob; m_pCurrentBlob = NULL; } } LRESULT CIPCChannel::OnCmdClientAttached(LPARAM lParam) { _ASSERTE(IsServer()); m_hwndRemote = reinterpret_cast(lParam); ExecuteAsync(cmdClientAttachedACK, 0, reinterpret_cast(m_hwndLocal)); m_Callback.OnIPCPeerConnected(); return 0; } LRESULT CIPCChannel::OnCmdClientAttachedACK(LPARAM lParam) { _ASSERTE(IsClient()); m_hwndRemote = reinterpret_cast(lParam); return 0; } LRESULT CIPCChannel::OnCmdPeerDisconnected(LPARAM lParam) { CloseChannel(FALSE); m_Callback.OnIPCPeerDisconnected(); return 0; } LRESULT CIPCChannel::OnCmdNotification(WORD wCode, LPARAM lParam) { return m_Callback.OnIPCNotificationReceived(wCode, lParam); } LRESULT CIPCChannel::OnCmdData(WORD wCode, LPARAM lParam) { LRESULT lResult = 0; CSharedBlob blob(static_cast(lParam)); if (blob.IsOpen()) { lResult = m_Callback.OnIPCDataReceived(wCode, blob.GetData(), blob.GetSize()); } return lResult; }