Terminating Accept
Hi All.
Recently I posted a question (http://groups.google.com/group/
microsoft.public.vc.mfc/browse_thread/thread/6ec9bd3dc80c408e#) about
a problem regarding closing an app using a system tray icon menu.
What I didn't know till now is that the problem was a
CAsyncSocket::Accept() function that was waiting for a connection and
probably blocked some messaging or something. Therfore the application
never exited. When I removed the accept function part - the closing of
the app via the system tray menu succeeded.
So I tried to move the listen/accept while loop into a separate
thread. I thought that this way the accept won't interfere in closing
the app. But then, when I tried to stop the "accept" with some closing
functions as you will see in the code, in order to allow the "Exit"
app in the menu to work, the CAsyncSocket::Close() crashed and the
accept didn't stop working anyway.
I read somewhere that you wouldn't like to put this loop in a thread.
My question is how to deal with this problem.
Actually, I think I need to somehow stop the "Accept" operation and
thus allow the system tray messages to work.
How do I do it?
Following is the class code. I removed some of the AboutBox code and
some other irrelevant code. I use a class for the system tray
functionality.
Thanks.
--------------------------------------------------------------------------
// PAADlg.cpp : implementation file
//
#include "stdafx.h"
#include "PAA.h"
#include "PAADlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
bool g_stop = false;
CEvent gEvent;
UINT RunListener(LPVOID lpParam);
// CPAADlg dialog
CPAADlg::CPAADlg(CWnd* pParent /*=NULL*/)
: CDialog(CPAADlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_DefaultMenuItemByPos = TRUE;
m_pParentWnd = pParent;
}
CPAADlg::~CPAADlg(){
g_stop = true;
//Trying to close Accept operation when exiting app
m_ListeningSocket.CancelBlockingCall();
m_ListeningSocket.ShutDown();
m_ListeningSocket.Close();
m_ConnectedSocket.Close();
WaitForSingleObject(gEvent.m_hObject, INFINITE);
m_autoLog.Close();
}
void CPAADlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CPAADlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_ICON_NOTIFY, OnTrayNotification)
END_MESSAGE_MAP()
// CPAADlg message handlers
BOOL CPAADlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// 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)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
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
//HICON hIcon = ::LoadIcon(NULL, IDI_ASTERISK);
HICON hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
if (!m_TrayIcon.Create(NULL, WM_ICON_NOTIFY, "Hello", hIcon,
IDR_POPUP_MENU))
return -1;
if(! CreateLogFile())
return FALSE;
gEvent.ResetEvent();
CWinThread* pThread = AfxBeginThread(RunListener ,this);
if(!pThread)
AfxMessageBox("Thread Error!");
return TRUE; // return TRUE unless you set the focus to a control
}
void CPAADlg::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.
BOOL CPAADlg::CreateLogFile()
{
CFileException e;
if(!m_autoLog.Open("c:\\AutoPaAgn.log", CFile::modeCreate|
CFile::modeNoTruncate|CFile::modeWrite, &e)){
CString s;
s.Format("%d", e.m_cause);
AfxMessageBox(s);
return FALSE;
}
return TRUE;
}
void CPAADlg::WriteToFile(CString a_sLine)
{
CTime tm = CTime::GetCurrentTime();
m_autoLog.WriteString(tm.Format("%H.%M.%S : ") + a_sLine);
}
LRESULT CPAADlg::OnTrayNotification(WPARAM wParam, LPARAM lParam)
{
//Return quickly if its not for this tray icon
if (wParam != m_tnd.uID)
return 0L;
CMenu menu, *pSubMenu;
// Clicking with right button brings up a context menu
if (LOWORD(lParam) == WM_RBUTTONUP)
{
if (!menu.LoadMenu(m_tnd.uID))
return 0;
pSubMenu = menu.GetSubMenu(0);
if (!pSubMenu)
return 0;
// Display and track the popup menu
CPoint pos;
GetCursorPos(&pos);
SetForegroundWindow();
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN, pos.x, pos.y, this, NULL);
PostMessage(WM_NULL, 0, 0);
menu.DestroyMenu();
}
else if (LOWORD(lParam) == WM_LBUTTONDBLCLK)
{
// double click received, the default action is to execute default
menu item
SetForegroundWindow();
UINT uItem;
if (m_DefaultMenuItemByPos)
{
if (!menu.LoadMenu(m_tnd.uID))
return 0;
pSubMenu = menu.GetSubMenu(0);
if (!pSubMenu)
return 0;
uItem = pSubMenu->GetMenuItemID(m_DefaultMenuItemID);
menu.DestroyMenu();
}
else
uItem = m_DefaultMenuItemID;
PostMessage(WM_COMMAND, uItem, 0);
}
return 1;
}
BOOL CPAADlg::SetMenuDefaultItem(UINT uItem, BOOL bByPos)
{
if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos ==
bByPos))
return TRUE;
m_DefaultMenuItemID = uItem;
m_DefaultMenuItemByPos = bByPos;
CMenu menu, *pSubMenu;
if (!menu.LoadMenu(m_tnd.uID))
return FALSE;
pSubMenu = menu.GetSubMenu(0);
if (!pSubMenu)
return FALSE;
::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID,
m_DefaultMenuItemByPos);
return TRUE;
}
void CPAADlg::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos)
{
uItem = m_DefaultMenuItemID;
bByPos = m_DefaultMenuItemByPos;
}
UINT RunListener(LPVOID lpParam)
{
CPAADlg * pDlg = (CPAADlg *)lpParam;
if (pDlg->m_ListeningSocket.Create(5555))
{
while(true)
{
pDlg->WriteToFile("Agent - Socket Created\n");
if (pDlg->m_ListeningSocket.Listen())
{
pDlg->WriteToFile("Agent - Wait for next message\n");
if (pDlg->m_ListeningSocket.Accept(pDlg->m_ConnectedSocket))
{
if(g_stop)
break;
pDlg->WriteToFile("Agent - Message Accepted\n");
char *pBuf = new char[1025];
int iBufSize = 1024;
int iRcvd;
iRcvd = pDlg->m_ConnectedSocket.Receive(pBuf, iBufSize, 0);
pDlg->WriteToFile("Agent - Message Received\n");
if (iRcvd == SOCKET_ERROR)
{
CString s;
s.Format("Agent - Receive Error: %d\n", GetLastError());
pDlg->WriteToFile(s);
}
else
{
pDlg->m_ConnectedSocket.GetPeerName(pDlg->PeerAddress(), pDlg-
PeerPort());
pBuf[iRcvd] = NULL;
pDlg->WriteToFile("Agent - Handle Message\n");
RegDeleteKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\AutoIt3Att\\Scripts\
\Flags");
if(pDlg->RunScript(pBuf))
pDlg->SendCompletionAck();
}
pDlg->m_ConnectedSocket.Detach();
}
else{
CString s;
s.Format("Agent - Accept Error: %d\n", GetLastError());
pDlg->WriteToFile(s);
}
}
else{
CString s;
s.Format("Agent - Listen Error: %d\n", GetLastError());
pDlg->WriteToFile(s);
}
}
}
gEvent.SetEvent();
//pDlg->m_ListeningSocket.Close();
return 0;
}
bool CPAADlg::RunScript(char a_sScriptName[])
{
CString s("Agent - RunScript ");
WriteToFile( s + a_sScriptName + "\n");
CString sScriptFullPath = sLibrary + a_sScriptName + ".au3";
CString cmdLine;
cmdLine.Format("\"c:\\Program Files\\AutoIt3\\AutoIt3.exe\" \"%s\"",
sScriptFullPath);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof STARTUPINFO;
PROCESS_INFORMATION pi;
BOOL res = CreateProcess(NULL,
cmdLine.GetBuffer(),
NULL,
NULL,
NULL,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi);
if (TRUE == res)
{
WriteToFile("Agent - RunScript - Process created\n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
return false;
}
void CPAADlg::SendCompletionAck(void)
{
while (1)
{
char Buf[10];
HKEY hKey;
DWORD type = REG_SZ;
long lRetCode;
DWORD size = 10;
lRetCode = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, "SOFTWARE\\AutoIt3Att\
\Scripts\\Flags", 0,KEY_READ,&hKey);
if (lRetCode == ERROR_SUCCESS){
WriteToFile("Agent - SendCompletionAck - Opened Complete Flag
registry Key\n");
lRetCode=::RegQueryValueEx(hKey,"Completed",NULL,NULL,(unsigned
char *)Buf,&size);
if(lRetCode == ERROR_SUCCESS){
Buf[1]=0;//the flag is 1 byte long: "1" or "0"
if (strcmp(Buf, "1") == 0)
{
WriteToFile("Agent - SendCompletionAck - Complete Flag registry
Key is 1\n");
CSocket sock;
if (sock.Create())//on any port
{
WriteToFile("Agent - SendCompletionAck Socket Created\n");
CString s;
s.Format("Agent - Peer IP is %s\n", m_sPeerAddress);
WriteToFile(s);
if (sock.Connect(m_sPeerAddress, 6666))
{
WriteToFile("Agent - SendCompletionAck Socket Connected\n");
int iAmtSent;
char buf[] ="1";
iAmtSent = sock.Send(buf, 1);
WriteToFile("Agent - Sent Completion Ack\n");
return;
}
else
{
CString s;
s.Format("Agent - SendCompletionAck Socket Connect Error: %d
\n", GetLastError());
WriteToFile(s);
}
}
else
{
CString s;
s.Format("Agent - SendCompletionAck Socket Create Error: %d\n",
GetLastError());
WriteToFile(s);
}
}else{
WriteToFile("Agent - SendCompletionAck - Complete Flag registry
Key is 0\n");
}
}
else
{
WriteToFile("Agent - SendCompletionAck - Failed to read Complete
Flag registry Key\n");
}
RegCloseKey(hKey);
}
else
{
WriteToFile("Agent - SendCompletionAck - Failed to open Complete
Flag registry Key\n");
}
Sleep(1000);
}//end while
}