📄 simplechatdlg.cpp
字号:
// here is two ways of handling the events being a subscriber
// since this thread is a CWinThread it has its won queue
// so I can just post this event into it
void CSimpleChatDlg::HandleNotification(CNotifEvent* pEvent)
{
HWND hwnd = GetSafeHwnd();
if (!hwnd)
return;
::PostMessage(hwnd, pEvent->event_id(), (WPARAM)pEvent, 0);
}
// here is an example of using subscriber's own queue.
// To turn this piece of code on set m_bHandleNotify = false in the constructor.
// The events are stored in subscribers CQueue and retrieved
// by polling the queue. For this thread wainting on an event
// would not work since it has to wait for Windows events
// on its own Windows queue. Therefore if I was to wait for
// an event from subscriber's queue, the UI would not update at all (hang)
// So better off just using the Microsoft's supplied queue
// and post messages there via PostMessage(...) aimed at a particualar
// window in a thread or PostThreadMessage(...) aimed at a thread in general
void CSimpleChatDlg::OnTimer(UINT nIDEvent)
{
CDialog::OnTimer(nIDEvent);
// if wrong event - return
if (m_nCheckForData != nIDEvent)
return;
while (IsThereEvent()) {
unsigned int sz = GetQueueSize();
char buff[20];
sprintf(buff, "%d", sz);
SetDlgItemText(IDC_QUEUE_SIZE, buff);
CNotifEvent* pEvent = GetEvent();
SendMessage(pEvent->event_id(), (WPARAM)pEvent);
delete pEvent;
}
// if no connection or no data has arrived - return
if (!m_NetStream.IsOpen())
return;
static netStatus status = nsUserDoesNtng;
static int nTimes = 0;
if (status != m_ctrlText.m_status.GetCode() || ++nTimes == 50) {
nTimes = 0;
SendLocalUserActivityStatus(m_ctrlText.m_status);
status = (netStatus)m_ctrlText.m_status.GetCode();
}
if (!m_NetStream.GetConnection()->CanRead())
return;
// data is here!
Receive();
}
void CSimpleChatDlg::OnDisconnect()
{
// send the logout message if not listening
if (m_acceptorThread.IsStoped())
SendLogout();
DisconnectAll();
}
void CSimpleChatDlg::OnDestroy()
{
UnhookWindowsHookEx(g_hook);
CDialog::OnDestroy();
// send the logout message
SendLogout();
// stop all threads
DisconnectAll();
// kill the polling the connection for data and for the events
KillTimer(m_nCheckForData);
// get rid of systray icon
SetupTrayIcon(false);
// get rid of the task bar
ShowWindow(SW_HIDE);
}
void CSimpleChatDlg::OnRestore()
{
// ShowWindow(SW_RESTORE);
SetupTrayIcon(false);
}
void CSimpleChatDlg::OnExit()
{
SendMessage(WM_CLOSE, 0, 0);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void CSimpleChatDlg::WriteYourName()
{
UpdateData();
CString strNick = "You";
if (!m_strYou.IsEmpty())
strNick += " (" + m_strYou + ")";
strNick += " say";
m_rtfStream << rtf::italic << rtf::bold << rtf::blue << strNick << rtf::nobold << rtf::noitalic;
ScrollToEnd();
}
void CSimpleChatDlg::WritePeerName()
{
CString strNick = "Peer";
if (!m_strPeer.IsEmpty())
strNick += " (" + m_strPeer + ")";
strNick += " says";
m_rtfStream << rtf::italic << rtf::bold << rtf::blue << strNick << rtf::nobold << rtf::noitalic;
ScrollToEnd();
}
void CSimpleChatDlg::WriteMsg(const char* strText)
{
m_rtfStream << " : " << rtf::bold << rtf::black << strText << rtf::nobold << std::endl;
ScrollToEnd();
}
void CSimpleChatDlg::WriteSystem(const char* strText)
{
m_rtfStream << rtf::bold << rtf::red << strText << std::endl;
ScrollToEnd();
}
void CSimpleChatDlg::ScrollToEnd()
{
int maxy = m_reChat.GetLineCount();
int miny = m_reChat.GetFirstVisibleLine() + GetVisibleHeight();
if (maxy > miny)
m_reChat.LineScroll(maxy - miny);
}
void CSimpleChatDlg::OnClearChat()
{
int maxy = m_reChat.GetLineCount();
int nPos = m_reChat.LineIndex(maxy-1);
int nLenght = m_reChat.LineLength(maxy);
m_reChat.SetSel(0, nPos + nLenght);
m_reChat.ReplaceSel("");
}
ushort CSimpleChatDlg::GetVisibleHeight()
{
return 12;
}
void CSimpleChatDlg::OnClear()
{
m_strText.Empty();
UpdateData(FALSE);
}
void CSimpleChatDlg::DisableControls()
{
GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE);
GetDlgItem(IDED_PORT)->EnableWindow(FALSE);
GetDlgItem(IDRB_CONNECT)->EnableWindow(FALSE);
GetDlgItem(IDRB_LISTEN)->EnableWindow(FALSE);
GetDlgItem(IDBT_GO)->EnableWindow(FALSE);
GetDlgItem(IDBT_SEND)->EnableWindow(TRUE);
GetDlgItem(IDBT_SEND_FILE)->EnableWindow(TRUE);
GetDlgItem(IDBT_DISCONNECT)->EnableWindow(TRUE);
}
void CSimpleChatDlg::EnableControls()
{
GetDlgItem(IDC_IPADDRESS)->EnableWindow(TRUE);
GetDlgItem(IDED_PORT)->EnableWindow(TRUE);
GetDlgItem(IDRB_CONNECT)->EnableWindow(TRUE);
GetDlgItem(IDRB_LISTEN)->EnableWindow(TRUE);
GetDlgItem(IDBT_GO)->EnableWindow(TRUE);
GetDlgItem(IDBT_SEND)->EnableWindow(FALSE);
GetDlgItem(IDBT_SEND_FILE)->EnableWindow(FALSE);
GetDlgItem(IDBT_SEND_CANCEL)->EnableWindow(FALSE);
GetDlgItem(IDBT_RECEIVE_CANCEL)->EnableWindow(FALSE);
GetDlgItem(IDST_PERCENTAGE_RECEIVED)->ShowWindow(SW_HIDE);
GetDlgItem(IDBT_DISCONNECT)->EnableWindow(FALSE);
}
void CSimpleChatDlg::OnUseThis()
{
UpdateData();
if (m_bUseMsg) {
GetDlgItem(IDCB_NICK_NAME)->EnableWindow(TRUE);
GetDlgItem(IDCB_WELCOME_MESSAGE)->EnableWindow(TRUE);
GetDlgItem(IDCB_GOODBYE_MESSAGE)->EnableWindow(TRUE);
} else {
GetDlgItem(IDCB_NICK_NAME)->EnableWindow(FALSE);
GetDlgItem(IDCB_WELCOME_MESSAGE)->EnableWindow(FALSE);
GetDlgItem(IDCB_GOODBYE_MESSAGE)->EnableWindow(FALSE);
}
}
void CSimpleChatDlg::OnKillfocusNickName()
{
CString strOldYou = m_strYou;
UpdateData();
// if nick name has not changed return
if (m_strYou == strOldYou) return;
// send a message, informing remote peer that the user has changed its nick name
SendLogin(nsNickChange);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CSimpleChatDlg message handlers
BOOL CSimpleChatDlg::OnInitDialog()
{
g_hook = SetWindowsHookEx(
WH_CALLWNDPROC, // hook type
CallWndProc, // hook procedure
NULL, // handle to application instance
AfxGetThread()->m_nThreadID // thread identifier
);
g_pDlg = this;
m_reChat.SubclassDlgItem(IDRE_MESSAGES, this);
CDialog::OnInitDialog();
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL) {
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty()) {
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// subclass the button
m_ctrlText.SubclassWindow(GetDlgItem(IDED_TEXT)->GetSafeHwnd());
// attach the stream
m_rtfStream.Attach(m_reChat.GetSafeHwnd());
m_msgConverter.Attach(this);
// find out the local address
CNetIPAddress address;
address.SetConnectString(CNetIPAddress::MakeLocalHostAddr(DEFAULT_PORT_N).c_str());
m_ctrlAddress.SetAddress(g_addr_stu(address.GetHostName()));
m_strPort = DEFAULT_PORT_N;
UpdateData(FALSE);
CButton* pbtnListen = (CButton*)GetDlgItem(IDRB_LISTEN);
CComboBox* pWBox = (CComboBox*)GetDlgItem(IDCB_WELCOME_MESSAGE);
CComboBox* pGBox = (CComboBox*)GetDlgItem(IDCB_GOODBYE_MESSAGE);
CComboBox* pNBox = (CComboBox*)GetDlgItem(IDCB_NICK_NAME);
pbtnListen->SetCheck(1);
pWBox->SetCurSel(0);
pGBox->SetCurSel(0);
pNBox->SetCurSel(0);
EnableControls();
OnUseThis();
m_time = CTime::GetCurrentTime();
// start checking the connection for data
SetTimer(m_nCheckForData, 100, 0);
CRect rtParent;
CRect rt;
GetWindowRect(rtParent);
GetDlgItem(IDST_PIN_POINT)->GetWindowRect(rt);
rt.OffsetRect(rtParent.TopLeft());
m_imgSmile.Load(IDB_ABOUT_OLD);
m_imgSmile.SetParent(GetSafeHwnd());
m_imgSmile.Move(rt.TopLeft());
m_imgBack.Load(IDB_BACK);
m_imgBack.SetParent(GetSafeHwnd());
m_imgBack.Visible(false);
// init the tray icon
// m_trayIcon.SetData(UWM_ON_NOTIFY, this, IDI_TRAY_ON, IDM_TRAY, lpszTip);
return TRUE; // return TRUE unless you set the focus to a control
}
void CSimpleChatDlg::SetupTrayIcon(bool bMin)
{
m_bMinimized = bMin;
if (m_bMinimized && m_pTrayIcon == 0) {
// create the tray
m_pTrayIcon = new CSystemTray;
m_pTrayIcon->Create(0, m_nmsgTray, lpszTip, AfxGetApp()->LoadIcon(IDI_ABOUT), IDM_TRAY);
// hide this window
ShowWindow(SW_HIDE);
}
else {
// get rid of the tray
delete m_pTrayIcon;
m_pTrayIcon = 0;
// show this window
ShowWindow(SW_SHOW);
}
}
void CSimpleChatDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX) {
CAboutDlg dlgAbout;
dlgAbout.DoModal();
} else
CDialog::OnSysCommand(nID, lParam);
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CSimpleChatDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (IsIconic())
{
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
CRect rect;
GetClientRect(&rect);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CSimpleChatDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL CSimpleChatDlg::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (nID == IDM_ABOUTBOX) {
CAboutDlg dlgAbout;
dlgAbout.DoModal();
return TRUE;
} else
return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
CNetAddress* CSimpleChatDlg::GetRemoteFileAcceptorAddr()
{
CNetIPAddress* pAddr = new CNetIPAddress;
pAddr->SetConnectString(m_strRemoteAddrFileAccept.c_str());
return pAddr;
}
void CSimpleChatDlg::OnSendCancel()
{
// get the thread's id these buttons control
CWnd* pSend = GetDlgItem(IDST_SEND);
unsigned long nThreadId = pSend->GetWindowContextHelpId();
// find the right thread
CThreadStorage& storage = g_getThreadStorage();
while (storage.Size() > 0) {
CNetThread* pThread = storage.GetAt(storage.Size() - 1);
// if this is the right thread, then abort transfer
// and wait for its self termination and self unregistration
if (pThread)
if (pThread->GetThreadId() == nThreadId) {
pThread->Stop();
break;
}
}
}
void CSimpleChatDlg::OnReceiveCancel()
{
// restore the thread's id these buttons control
CWnd* pReceive = GetDlgItem(IDST_RECEIVE);
unsigned long nThreadId = pReceive->GetWindowContextHelpId();
// find the right thread
CThreadStorage& storage = g_getThreadStorage();
while (storage.Size() > 0) {
CNetThread* pThread = storage.GetAt(storage.Size() - 1);
// if this is the right thread, then abort transfer
// and wait for its self termination and self unregistration
if (pThread)
if (pThread->GetThreadId() == nThreadId) {
pThread->Stop();
break;
}
}
}
LRESULT CALLBACK CallWndProc(
int nCode, // hook code
WPARAM wParam, // current-process flag
LPARAM lParam // message data
)
{
if (nCode != HC_ACTION)
return CallNextHookEx(g_hook, nCode, wParam, lParam);
HWND hDlg = g_pDlg->GetSafeHwnd();
HWND hActive = ::GetActiveWindow();
if (hDlg != hActive) {
g_pDlg->m_ctrlText.m_status.SetCode(nsUserDoesNtng);
g_pDlg->m_ctrlText.m_status.SetText("The remote peer is away");
} else {
if (g_pDlg->m_ctrlText.m_status.GetCode() == nsUserDoesNtng) {
g_pDlg->m_ctrlText.m_status.SetCode(nsUserIsHere);
g_pDlg->m_ctrlText.m_status.SetText("The remote peer is reading messages");
}
}
return CallNextHookEx(g_hook, nCode, wParam, lParam);
}
void CSimpleChatDlg::OnConnect()
{
SetDlgItemText(IDED_ADDRESS, "Peer's IP address:");
}
void CSimpleChatDlg::OnListen()
{
SetDlgItemText(IDED_ADDRESS, "Your IP address:");
}
void CSimpleChatDlg::OnShowBk()
{
m_imgBack.Visible(!m_imgBack.IsVisible());
Invalidate();
}
BOOL CSimpleChatDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
CMDC mdc(pDC, rect);
mdc.FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
m_imgBack.DrawMaskedBlended(&mdc, RGB(255, 255, 255), 40);
m_imgSmile.DrawMasked(&mdc, RGB(255, 0, 0));
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -