The
Jim
Patchell Windows Programming Page
First
Posted
January 1, 2005
Updated January 20,
2014
Contents:
Overlapped RS232
Simple Soft Synth
Mutex Class
Memory Heap Class
Message Queue Class
Sending Messages to Worker Thread
Overlapped RS232 Programming
January
1, 2005
If you have ever tried to write a
program that
accessed the comm ports under Win32, you have probably been overwhelmed
by the large number of convoluted functions you have to deal with in
order to do this. It is posible to open up the RS232 port on
Non-overlapped mode, however, there are several problems with doing
this, and if you have done it, you may have run into them. By
using the overlapped mode, the comm ports do work pretty much as you
would expect, although, still not, in my opinion, perfectly.
Of
course, there are probably still some features I don't know about that
would even cure these problems.
What you will find here is a zip file of
a skeleton
program that opens up an RS232 port and provides functions for reading
and writing to the port.
Now, one of the problems still with
using the
Overlapped mode is that you need to have a thread that reads the
characters that come back into the PC. In the code, you will
find
this in a function called WorkerThread.
Yeah, not exactly an original name, but what the heck. This
worker thread is pretty simple. It reads the character in and
prints it into a static text box in the main dialog. Now in a
real program you will most likely have some sort of parser, be it
simple or complex, that will look for messages in the data coming
back. Once you have located your messages you can do several
things. You can act on them directly, or you can send a
notification back to the main dialog box by using PostMessage and
sending user defined
messages, just like I did for the message that notifies the main dialog
box that the thread has stopped.
As of January 1, 2005, I have not
actually tested
this code, although, most of it has been used before (that is no
garentee). Still for the time being, it should give you a
good
idea of how to proceed.
Source
Code for
Overlapped RS232
A
Simple
Soft Synth for MicroSquish Windows
March
9, 2005
This is a very simple softsynth that I
did for
running under Microsoft Windows. It should run with
Windows98,
Windows2000, Windows XP and Windows ME. I have only tried it
on
Windows XP running on a 2GHz Pentium. There is a chance a
slower
computer could sound strange. So, what you will find here is
the
source code and an executable for a very simple program that compiles,
hopefully, with Microsoft Visual C++ 6.0. I cannot predict
what
it will do with other versions of the compiler.
There is not a whole lot that I can
think of to say
about this program. Basically, I open up an audio out channel
and
set up two buffers. The buffers are then ping-ponged as they
empty out. There is a synth engine routine that is called
that
fills the buffers up with data when a buffer is ready.
Oh, yes, there is a simple little
sequencer that
plays a couple of little tunes.
The modules that I implemented are a
VCO, Multimode
VCF, VCA, and a simple envelope generator.
Source
Code for Soft Synth
Program
Source Code for Mutex
Source Code for Heap
I only turned some C functions into a C++ class. The
functions
originally came from the run time library for WinAVR. You
will
find the original copyright notice in the cpp file. I don't
know
if this was all nessesary or not, but it sure made my life a lot
easier. Thank you Joerg Wunsch.
Source Code for Queue Class
Sending
Messages to a Worker Thread
January 20, 2014
The
reality is if you need to send messages to a worker thread, use the GUI
thread model for CWinThread. Even if you are not going to be
doing a GUI, you can still use it as such, and life will probably be a
whole lot easier. OH, you are a control freak! Just
like
me. OK, well, here is what I did.
I found a really useful article on the "Code Project" called Using
Worker Threads By Joseph
M. Newcomer, 5 Apr 2001. It is located at :
http://www.codeproject.com/Articles/552/Using-Worker-Threads
Now
at first I felt kind of guilty about plagiarizing
his code,
but as it tuns out, it appears that it was taken right out of the
source code for MFC itself. But, I digress.
One of the
things it said in the article is using CWinThread::ResumeThread is not
a good thing. I discovered that it was pretty impossible to
get
along without it. The problem I had was that the worker
thread
would start using things before they were initialized.
So,
I ended up having to use ResumeThread, and so far, I have seen no ill
effects from it.
OK, now for the code. First, let us take a look at the header
file for CMyThread.
#include
"MSG.h"
enum { MT_SHUTDOWN = 0, MT_RUNNING, MT_MESSAGE, MT_ERROR =
0xffffffe,MT_TIMEOUT };
/////////////////////////////////////////////////////////////////////////////
// CMyThread thread
class CMyThread : public CWinThread
{
DECLARE_DYNCREATE(CMyThread)
protected:
CMyThread(){};
// protected constructor used by dynamic creation
// Attributes
public:
// Operations
public:
CMsgQueue * m_MSGQ;
int m_NwaitObjs;
HANDLE m_WaitObjects[16];
DWORD m_WaitRetVals[16];
void ClearWaitObjects();
int SetWaitObject(HANDLE hObj,DWORD
RetVal);
void Continue();
void Pause(void);
DWORD Wait(void);
void ShutDown();
static CMyThread *
BeginThread(AFX_THREADPROC pProc, void *pP,int MsgQDepth);
// Overrides
// ClassWizard generated virtual
function overrides
//{{AFX_VIRTUAL(CMyThread)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL
// Implementation
protected:
HANDLE m_PauseEvent;
HANDLE m_ShutdownEvent;
CMyThread(AFX_THREADPROC pProc, void
*pP);
virtual ~CMyThread();
// Generated message map functions
//{{AFX_MSG(CMyThread)
// NOTE -
the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
|
And here is the code for implementation.
Constructor
IMPLEMENT_DYNCREATE(CMyThread,
CWinThread)
CMyThread::CMyThread(AFX_THREADPROC pProc, void
*pP):CWinThread(pProc,pP)
{
m_bAutoDelete = FALSE;
m_ShutdownEvent =
::CreateEvent(NULL, // security
TRUE, // manual-reset
FALSE, // not signaled
NULL); // anonymous
m_PauseEvent =
::CreateEvent(NULL,
// security
TRUE, // manual-reset
TRUE, // signaled
NULL); // anonymouse
this->m_NwaitObjs = 0;
memset(this->m_WaitObjects,0,sizeof(HANDLE) * 16);
this->m_MSGQ = 0;
}
|
This
is the constructor for the object. Mostly we are creating a
bunch
of event objects. m_ShutdownEvent is the event we trigger
when
we want the thread to shut down. m_PauseEvent can be used to
make
the thread run continuously. When m_PauseEvent is
Set, the
event will always run. And finally we initialize the wait
objects m_WaitObjects to zero. This is an array of
HANDLEs
that are used to let our thread what it needs to do. It will
contain the two EVENTs listed above as well as any others we
decide to add.
Begin Thread
CMyThread * CMyThread::BeginThread(AFX_THREADPROC
pProc, void *pP,int MsgQDepth)
{
CMyThread * thread = new
CMyThread(pProc, pP);
if(!thread->CreateThread(CREATE_SUSPENDED,0 ))
// if(!thread->CreateThread())
{ /* failed ? */
delete
thread;
thread = 0;
} /* failed */
else
{
//-----------------------------
// setup
default wait objects
//-----------------------------
thread->SetWaitObject(thread->m_ShutdownEvent,MT_SHUTDOWN);
thread->SetWaitObject(thread->m_PauseEvent,MT_RUNNING);
thread->m_MSGQ = new CMsgQueue(MsgQDepth);
thread->SetWaitObject(thread->m_MSGQ->GetSem()->GetHandle(),MT_MESSAGE);
}
return thread;
}
|
OK,
here is the crux of the whole thing. When I first saw this
static
member function, I was a bit confused because I forgot that a static
member function is more like a real C function that a C++ class.
Now, if you were to look at the source code for the MFC
function
AfxBeginThread you will see that a lot of this is just pulled right out
of that code. And the reason I looked at that code was
because I
could find no documentation on a lot of the functions used, such as the
constructor CWinThread(proc,pP) and the create thread function with no
parameters. Evidently, they do exist, as the code works (at
least with Visual Studio 6) , so one of these days I need to look in
the MFC source code and find out what the deal is.
I
just looked at the code for CWinThread, and sure enough, there are
undocumented methodes in the class. It would appear that
Microsoft wanted to encourage the use of AfxBeginThread.
After
the tread is created, we add a few event objects to the mess.
We
add the events for shutting down the thread, pausing and finally, the
semaphore from the Message Queue (see above) that we will use to send
messages to the thread. We are using a semaphore as it will
keep
track of how many times it has been signaled so we won't miss any of
the messages.
Wait Function
DWORD CMyThread::Wait()
{
DWORD result =
::WaitForMultipleObjects(m_NwaitObjs, m_WaitObjects, FALSE,
INFINITE);
switch(result)
{ /* result */
case
WAIT_TIMEOUT:
result = MT_TIMEOUT;
break;
default:
if(result <= WAIT_OBJECT_0+16)
{
result =
m_WaitRetVals[result - WAIT_OBJECT_0];
}
else
result = MT_ERROR;
break;
} /* result */
return result;
}
|
When any of the events in the m_WaitObjects
table are triggered (signaled), this function will return an integer
value that represents the event. I used a table to
look up
these values, since I had no idea what the value of WAIT_OBJECT_0 might
be, or could be in the future. So, I made sure that I would
always get a value that I knew. This function is a bit
different
than the one described in the article I mentioned above.
Anyway,
what this program does is it allows you to start up the
worker
thread, and then send a message to it. The worker thread then
sends a message back to theapplication view window where it is
displayed. I know that this is a useless progrom but it does
demonstrate how the message passing is done. The worker
thread
uses the standard CWnd::PostMessage message function to send messages
back.
Source Code for the Project
The above was built with Visual Studio 6.0.
Home
Bye...