Click to See Complete Forum and Search --> : New to threads and messages


Jess N
August 20th, 1999, 04:05 AM
I am trying to write a program which constantly polls the serial port waiting for an input (why I'm bothering I have no idea - I'm sure millions of other people have already done it successfully!) but anyway, I have created a new thread (using AfxBeginThread) to constantly check, and send a message to the main thread when it finds anything in the buffer:

UINT ThreadProc(LPVOID pParam)//global func called by the thread
{
CSerialDlg* pParent=(CSerialDlg*)pParam;
pParent->ReadSerial();
return 0;
}

void CSerialDlg::ReadSerial() //member function called by the global function
{
CString Output = "";
unsigned char OutputBuffer[1024];
int BytesRead;
CString Text;

while(1)
{
while((BytesRead = ReadComms(OutputBuffer, 1024)) > 0)
{
OutputBuffer[BytesRead] = '\0';
Output = OutputBuffer;
m_pOutputString = &Output;
this->PostMessage(WM_SERIAL, 0, 0); //it crashes somewhere around here
}
::Sleep(0);
}
}



The problem I have is that in release mode the program crashes after the second time the message is posted. This happens under NT and 95. In 95 I get an invalid page fault and in NT it just says "the memory cannot be read".

The message is declared as follows:

#define WM_SERIAL WM_USER+100

BEGIN_MESSAGE_MAP(CSerialDlg, CDialog)
//{{AFX_MSG_MAP(CSerialDlg)
...
ON_THREAD_MESSAGE(WM_SERIAL, OnSerialMessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()



and in the .h file:

// Generated message map functions
//{{AFX_MSG(CSerialDlg)
...
afx_msg void OnSerialMessage();

//}}AFX_MSG
DECLARE_MESSAGE_MAP()



the message handler function is as follows:

void CSerialDlg::OnSerialMessage()
{
m_Output += *m_pOutputString;
m_Output.Replace("\r\n", "\n");
m_Output.Replace("\n", "\r\n");
UpdateData(FALSE);
}



I hope I have given enough information for someone to be able to help with this problem. This is my first attempt at working with threads or messages, so I really don't have much idea what I'm doing!

Thanks,
Jess

August 20th, 1999, 05:26 AM
Hi,
I think the problem is that you are changing the String (m_pOutputString) in the thread (ReadSerial) while you access the String in the Dialog (OnSerialMessage).
One possibility is to allocate a String in the thread, send it with the PostMessage to the Dialog and delete the String in the Dialog when you made the access.

Hope this helps you!

Jess N
August 20th, 1999, 05:55 AM
Hi,

Thanks for your answer.. I was worried that accessing the string in both threads might cause problems, but unfortunately I don't think it causes *this* problem. Even if I comment out all the lines referring to the output string (or even all the lines in OnSerialMessage) it still crashes in the same way!

Any other suggestions? :)

Jess

Jess N
August 20th, 1999, 06:04 AM
P.S
Sorry for my ignorance but how do you send a CString with a PostMessage?

arrizza
August 20th, 1999, 06:56 AM
Interesting point about the polling. If you use ReadFile it will block and nicely tell you when a byte has come in.

re: release mode. Set up your project to generate .pdb files and use the debugger to see what's going on.

re: posting a message with an address. Since the msg loop and the Post() are in the same Process, you can just pass the address in lParam or wParam.

Still don't know why your code is crashing, though :)

John A

August 20th, 1999, 06:59 AM
Hi,
sorry, I ignored your MessageMap. ON_THREAD_MESSAGE you can only use if your class is derived from CWinThread. In your case you should use ON_MESSAGE(WM....,OnSerialMessage)
Prototyp: ...::OnSerialMessage(WPARAM wParam, LPARAM lParam)
You can use the lParam for example for your String.

Hope itīs working now.

Jess N
August 20th, 1999, 07:10 AM
Yay!! It works now, thanks Anonymous. I had actually changed the ON_THREAD_MESSAGE to ON_MESSAGE just after my first post, but still couldn't understand why it was crashing - I can't believe it was something as simple as leaving out the parameters in the OnSerialMessage function. I somehow thought they were optional :)

Thanks again,
Jess

Jess N
August 20th, 1999, 07:15 AM
Why thankyou Arrizza, debugging in release mode.. I didn't realise it could be done!

The code is fixed with regard to the crashing, but I will take your advice about how to pass the string.

I'd love to give Anon some points for fixing the crash which has been bugging me for days, but sadly he/she is anonymous so I can't!

August 22nd, 1999, 09:29 PM
I have the same problem as this although mine is a little different.
It ONLY posts the message back to my main Dialog-based application the first
time PostMessage() or SendMessage() has been issued. On the next calls does
not do anything. It skips the PostMessage() and/or SendMessage() function.
Could someone help me?

Thanks

August 22nd, 1999, 09:47 PM
My problems is somewhat similar to Jess'. However, mine does not crash but instead it ignores succeeding calls to PostMessage() and/or SendMessage().

I have a dialog based application where i call my thread like this:


DWORD readstatusID;
ReadAndStatusThreadInfo readThreadInfo;

readThreadInfo.m_hwndMainDialogHandle = AfxGetMainWnd()->m_hWnd;

g_readThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadDataAndStat, (LPVOID)&readThreadInfo, 0, &readstatusID);

then my Thread Procedure is Something like this:
:
:
if(bytesRead != MAX_READ_BUFFER)
{
::SendMessage(pInfo->m_hwndMainDialogHandle, WM_USER_READSTATUS_MSG, STATUS_WINDOW, READ_TIMEOUT);
AfxMessageBox("Sample String!");
}

:
:
LRESULT CSerialComDlg::OnNewMessageString(WPARAM msgDest, LPARAM msgType)
{
if(int(msgDest) == DATA_WINDOW)
AppendToReadWindow(int(msgType));
else
AppendToStatusWindow(int(msgType));

return 0;
}

AppendToStatusWindow() simply adds a string to my list box.

The problem is that it only displays the string during the first time it is called. and not everytime. But the call to AfxMessageBox("Sample String"),
after the PostMessage() is always done.

Can someone enlighten me?

Thanks.

Butch