// CommunicatorView.cpp : implementation of the CCommunicatorView class // #include "stdafx.h" #include "Communicator.h" #include "CommunicatorDoc.h" #include "CommunicatorView.h" #include "SendDataDlg.h" #include "OXBlob.h" #include // for OnIdleUpdateCmdUI #include // For mutex support #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CCommunicatorView #pragma data_seg(".sdata") // Store the usage count of this application so that multiple instances will // cascade nicely on the screen LONG nUsageCount = 0; #pragma data_seg() IMPLEMENT_DYNCREATE(CCommunicatorView, CFormView) BEGIN_MESSAGE_MAP(CCommunicatorView, CFormView) //{{AFX_MSG_MAP(CCommunicatorView) ON_BN_CLICKED(IDC_CONNECT_SERVER, OnConnectServer) ON_BN_CLICKED(IDC_DISCONNECT_CLIENT, OnDisconnectClient) ON_BN_CLICKED(IDC_DISCONNECT_SERVER, OnDisconnectServer) ON_BN_CLICKED(IDC_LISTEN, OnListen) ON_BN_CLICKED(IDC_SEND_CLIENT, OnSendClient) ON_BN_CLICKED(IDC_SEND_SERVER, OnSendServer) ON_BN_CLICKED(IDC_SHUTDOWN, OnShutdown) ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CCommunicatorView construction/destruction CCommunicatorView::CCommunicatorView() : CFormView(CCommunicatorView::IDD) { //{{AFX_DATA_INIT(CCommunicatorView) m_sLocalAddress = _T(""); m_nLocalPort = 1000; m_sRemoteAddress = _T(""); m_nRemotePort = 1000; //}}AFX_DATA_INIT // TODO: add construction code here } CCommunicatorView::~CCommunicatorView() { } void CCommunicatorView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); //{{AFX_DATA_MAP(CCommunicatorView) DDX_Control(pDX, IDC_CANCEL, m_wndCancel); DDX_Control(pDX, IDC_LOCAL_PORT_LABEL, m_wndLocalPortLabel); DDX_Control(pDX, IDC_SERVER_GROUP, m_wndServerGroup); DDX_Control(pDX, IDC_REMOTE_ADDRESS_LABEL, m_wndRemoteAddressLabel); DDX_Control(pDX, IDC_REMOTE_PORT_LABEL, m_wndRemotePortLabel); DDX_Control(pDX, IDC_LOCAL_ADDRESS_LABEL, m_wndLocalAddressLabel); DDX_Control(pDX, IDC_CLIENT_GROUP, m_wndClientGroup); DDX_Control(pDX, IDC_CLIENT_ADDRESSES_LABEL, m_wndClientAddressLabel); DDX_Control(pDX, IDC_SEND_SERVER, m_wndSendServer); DDX_Control(pDX, IDC_DISCONNECT_SERVER, m_wndDisconnectServer); DDX_Control(pDX, IDC_CONNECT_SERVER, m_wndConnectServer); DDX_Control(pDX, IDC_REMOTE_PORT, m_wndRemotePort); DDX_Control(pDX, IDC_REMOTE_ADDRESS, m_wndRemoteAddress); DDX_Control(pDX, IDC_DISCONNECT_CLIENT, m_wndDisconnectClient); DDX_Control(pDX, IDC_SEND_CLIENT, m_wndSendClient); DDX_Control(pDX, IDC_SHUTDOWN, m_wndShutdown); DDX_Control(pDX, IDC_LISTEN, m_wndListen); DDX_Control(pDX, IDC_LOCAL_PORT, m_wndLocalPort); DDX_Control(pDX, IDC_LOCAL_ADDRESS, m_wndLocalAddress); DDX_Control(pDX, IDC_CLIENT_ADDRESSES, m_wndClientAddresses); DDX_Control(pDX, IDC_RECEIVED_DATA, m_wndReceivedData); DDX_Text(pDX, IDC_LOCAL_ADDRESS, m_sLocalAddress); DDX_Text(pDX, IDC_LOCAL_PORT, m_nLocalPort); DDX_Text(pDX, IDC_REMOTE_ADDRESS, m_sRemoteAddress); DDX_Text(pDX, IDC_REMOTE_PORT, m_nRemotePort); //}}AFX_DATA_MAP } BOOL CCommunicatorView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CFormView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CCommunicatorView diagnostics #ifdef _DEBUG void CCommunicatorView::AssertValid() const { CFormView::AssertValid(); } void CCommunicatorView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); } CCommunicatorDoc* CCommunicatorView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCommunicatorDoc))); return (CCommunicatorDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CCommunicatorView message handlers void CCommunicatorView::OnConnectServer() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnConnectServer : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } UpdateData(TRUE); // If remote address is not filled out, try a local connection if (m_sRemoteAddress.IsEmpty()) { m_sRemoteAddress = GetDocument()->GetLocalAddress(); UpdateData(FALSE); } // Do not use the specified local port, let winsockets pick one if (!GetDocument()->ConnectServer(m_sRemoteAddress, m_nRemotePort, 0)) AfxMessageBox(IDS_FAILED_CONNECT, MB_ICONEXCLAMATION); m_nLocalPort = GetDocument()->GetLocalPort(); UpdateData(FALSE); } void CCommunicatorView::OnDisconnectClient() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnDisconnectClient : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } UINT nSelCount = m_wndClientAddresses.GetSelCount(); if (0 < nSelCount) { int index; int* rgSels = new int[nSelCount]; m_wndClientAddresses.GetSelItems(nSelCount, rgSels); for (index = (int)nSelCount - 1; 0 <= index; index--) GetDocument()->DisconnectClient(m_wndClientAddresses.GetItemData(rgSels[index])); delete rgSels; } } void CCommunicatorView::OnDisconnectServer() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnDisconnectServer : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } GetDocument()->Shutdown(); } void CCommunicatorView::OnListen() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnListen : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } UpdateData(TRUE); if (!GetDocument()->Listen(m_nLocalPort)) AfxMessageBox(IDS_FAILED_LISTEN, MB_ICONEXCLAMATION); } void CCommunicatorView::OnSendClient() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnSendClient : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } COXCommMsg* pCommMsg = new COXCommMsg; CSendDataDlg dlg(pCommMsg); if (dlg.DoModal() == IDOK) { UINT nSelCount = m_wndClientAddresses.GetSelCount(); if (0 < nSelCount) { int index; int* rgSels = new int[nSelCount]; m_wndClientAddresses.GetSelItems(nSelCount, rgSels); for (index = 0; index < (int)nSelCount; index++) GetDocument()->Send(m_wndClientAddresses.GetItemData(rgSels[index]), pCommMsg); delete rgSels; } } delete pCommMsg; } void CCommunicatorView::OnSendServer() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnSendServer : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } COXCommMsg* pCommMsg = new COXCommMsg; CSendDataDlg dlg(pCommMsg); if (dlg.DoModal() == IDOK) GetDocument()->SendServer(pCommMsg); delete pCommMsg; } void CCommunicatorView::OnShutdown() { if (GetDocument()->IsBlocking()) { TRACE(_T("CCommunicatorView::OnShutdown : Communicator is still blocking\n")); MessageBeep(0xFFFF); return; } GetDocument()->Shutdown(); } void CCommunicatorView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { UNREFERENCED_PARAMETER(pSender); CCommunicatorDoc::CHintData* pHintData = (CCommunicatorDoc::CHintData*)pHint; CString sText; int index; switch(lHint) { case CCommunicatorDoc::NotifyAddClient: // Add the client address to the list sText.Format(_T("%i. %s (%i)"), pHintData->m_hClient, (LPCTSTR)pHintData->m_sClientAddress, pHintData->m_nClientPort); index = m_wndClientAddresses.AddString(sText); m_wndClientAddresses.SetItemData(index, pHintData->m_hClient); // If nothing is selected, select this item if (m_wndClientAddresses.GetSelCount() == 0) m_wndClientAddresses.SetSel(index); break; case CCommunicatorDoc::NotifyRemoveClient: // Remove the client address from the list for (index = 0; index < m_wndClientAddresses.GetCount(); index++) { if ((int)m_wndClientAddresses.GetItemData(index) == pHintData->m_hClient) m_wndClientAddresses.DeleteString(index); } // If nothing is selected, select the first one if (m_wndClientAddresses.GetSelCount() == 0) m_wndClientAddresses.SetSel(0); break; case CCommunicatorDoc::NotifyRemoveAllClients: // Remove all the client address from the list m_wndClientAddresses.ResetContent(); break; case CCommunicatorDoc::NotifyAddData: // Show the received data ShowData(pHintData); break; default: break; } } void CCommunicatorView::ShowData(CCommunicatorDoc::CHintData* pHintData) { CString sText; CString sValue; if (pHintData->m_pCommMsg == NULL) { if (pHintData->m_nDataLength != 0) sText.Format(_T("%i. (length = %i)\r\n"), pHintData->m_hClient, pHintData->m_nDataLength); else sText.Format(_T("%i. (length = unknown)\r\n"), pHintData->m_hClient); AddText(sText); return; } sText.Format(_T("%i. Array of size %i\r\n"), pHintData->m_hClient, pHintData->m_pCommMsg->GetSize()); AddText(sText); COXVariant variant; UINT nOleType; UINT nType; for (int index = 0; index < pHintData->m_pCommMsg->GetSize(); index++) { // Convert variant to string to visualize variant = pHintData->m_pCommMsg->GetAt(index); nOleType = V_VT(&variant); for (nType = 0; (nType < COXCommMsg::m_nArgumentTypesCount) && (nOleType != (UINT)COXCommMsg::m_types[nType]); nType++) ; // ... Must have found the type ASSERT(nType < COXCommMsg::m_nArgumentTypesCount); sValue.Empty(); TRY { if (nOleType != COXCommMsg::ATBlob) { if (V_VT(&variant) == COXCommMsg::ATError) // ... Variant is a union, just change the type // oleVariant.lVal= oleVariant.scode ; V_VT(&variant) = COXCommMsg::ATI4; variant.ChangeType(COXCommMsg::ATStr); sValue = V_BSTR(&variant); } else { ASSERT(nOleType == COXCommMsg::ATBlob); CString sTempPath; CString sTempFileName; COXBlob blob; VERIFY(::GetTempPath(_MAX_PATH, sTempPath.GetBuffer(_MAX_PATH)) != 0); sTempPath.ReleaseBuffer(); VERIFY(::GetTempFileName(sTempPath, _T("BLB"), 0, sTempFileName.GetBuffer(_MAX_PATH)) != 0); sTempFileName.ReleaseBuffer(); blob = variant; blob.WriteRaw(sTempFileName); sValue.Format(_T(" (stored as %s)"), blob.GetSize(), sTempFileName); } } END_TRY sText.Format(_T("\t%i. (%s) %s\r\n"), index + 1, (LPCTSTR)COXCommMsg::m_typeNames[nType], (LPCTSTR)sValue); AddText(sText); } } void CCommunicatorView::AddText(LPCTSTR pszText) { LONG nWindowTextLength; nWindowTextLength = m_wndReceivedData.GetWindowTextLength(); m_wndReceivedData.SetSel(nWindowTextLength, nWindowTextLength); m_wndReceivedData.ReplaceSel(pszText); } void CCommunicatorView::OnInitialUpdate() { CFormView::OnInitialUpdate(); // Show local server name m_sLocalAddress = GetDocument()->GetLocalAddress(); UpdateData(FALSE); // Fit frame around view ResizeParentToFit(FALSE); // Fit mainframe around frame, do this only once static bMainFrameResized = FALSE; if (!bMainFrameResized) { bMainFrameResized = TRUE; // Get the size of frame and main frame CRect frameRect; CRect mainFrameRect; CRect mainFrameClientRect; GetParentFrame()->GetWindowRect(frameRect); AfxGetMainWnd()->GetWindowRect(mainFrameRect); AfxGetMainWnd()->GetClientRect(mainFrameClientRect); // Resize the mainframe so that this view frame will completely fill the client area mainFrameRect.right += frameRect.Width() - mainFrameClientRect.Width(); mainFrameRect.bottom += frameRect.Height() - mainFrameClientRect.Height(); // Take other windows into account that also populate the main frames client area CWnd* pChild; CRect childRect; pChild = AfxGetMainWnd()->GetWindow(GW_CHILD); while (pChild != NULL) { // ... Skip the MDI frame window if (pChild != GetParentFrame()->GetParent()) { pChild->GetWindowRect(childRect); // Statusbar and buttonbar take up the entire width (or height) // Use the smallest of the two if (childRect.Height() < childRect.Width()) mainFrameRect.bottom += childRect.Height(); else mainFrameRect.right += childRect.Width(); } pChild = pChild->GetWindow(GW_HWNDNEXT); } // Position multiple instance next to each other CMutex mutex(FALSE, _T("COMMUNICATOR_MOVE")); // ... Lock the mutex, destructor will unlock CSingleLock lock(&mutex, TRUE); nUsageCount++; // If at most two instances are running if (nUsageCount <= 2) { // Put main frame in top left corner (0,0) mainFrameRect.right -= mainFrameRect.left; mainFrameRect.bottom -= mainFrameRect.top; mainFrameRect.left = 0; mainFrameRect.top = 0; // Position it next to the other instance (if it exists) mainFrameRect.left = mainFrameRect.right * (nUsageCount - 1); mainFrameRect.right = mainFrameRect.right * nUsageCount; } AfxGetMainWnd()->MoveWindow(mainFrameRect); } } void CCommunicatorView::OnIdleUpdateCmdUI() { BOOL bClientSelected = (0 < m_wndClientAddresses.GetSelCount()); BOOL bOpen = GetDocument()->IsOpen(); BOOL bServer = FALSE; BOOL bClient = FALSE; if (bOpen) { bServer = GetDocument()->IsListening(); bClient = !bServer; } // Conditionally disable controls // Server m_wndServerGroup. EnableWindow(!bOpen || bServer); m_wndLocalAddressLabel. EnableWindow(!bOpen); m_wndLocalAddress. EnableWindow(!bOpen); m_wndLocalPortLabel. EnableWindow(!bOpen); m_wndLocalPort. EnableWindow(!bOpen); m_wndListen. EnableWindow(!bOpen); m_wndShutdown. EnableWindow(bServer); m_wndSendClient. EnableWindow(bServer && bClientSelected); m_wndDisconnectClient. EnableWindow(bServer && bClientSelected); m_wndClientAddressLabel.EnableWindow(bServer); m_wndClientAddresses. EnableWindow(bServer); // Client m_wndClientGroup. EnableWindow(!bOpen || bClient); m_wndRemoteAddressLabel.EnableWindow(!bOpen); m_wndRemoteAddress. EnableWindow(!bOpen); m_wndRemotePortLabel. EnableWindow(!bOpen); m_wndRemotePort. EnableWindow(!bOpen); m_wndConnectServer. EnableWindow(!bOpen); m_wndSendServer. EnableWindow(bClient); m_wndDisconnectServer. EnableWindow(bClient); // Global m_wndCancel. EnableWindow(bOpen); } void CCommunicatorView::PostNcDestroy() { // Relase this instance count CMutex mutex(FALSE, _T("COMMUNICATOR_MOVE")); // ... Lock the mutex, destructor will unlock CSingleLock lock(&mutex, TRUE); nUsageCount--; CFormView::PostNcDestroy(); }