Re: Creating a simple windows messaging app



See below...
On Thu, 10 Jul 2008 15:50:33 -0700, "Nick Schultz" <nick.schultz@xxxxxxxx> wrote:


"Scott McPhillips [MVP]" <org-dot-mvps-at-scottmcp> wrote in message
news:%231zjOet4IHA.3484@xxxxxxxxxxxxxxxxxxxxxxx
"Nick Schultz" <nick.schultz@xxxxxxxx> wrote in message
news:eCclgps4IHA.4868@xxxxxxxxxxxxxxxxxxxxxxx
Hi there,

a broker app that receives packets from a canbus and pushes them out to
multiple applications.

there are two types of threads the broker will have: the main loop and
the "app" thread

The broker has a main loop that essentially sits and waits for two types
of messages:
-wm_canlib :
****
DO NOT define user-defined messages that start with WM, ever. It only confuses people,
including future programmers who will try to find them in the MSDN. ALWAYS use a unique
prefix that is not in use already. For example, CAN_DATA would be a reasonable name; many
of us use UWM_ or WMU_ as prefixes (the U indication user). But NEVER use WM_, that
prefix is reserved, and it is just confusing to use it
****
canlib notifies the broker by sending a wm_canlib message to a window
handle that I assign. the broker then takes the packet and then gives
each application thread a copy of the packet.
-(userdefined appregister) :
front end applications that want to receieve packets will broadcast
this message to get setup for receiving packets.
the main loop will then create a packet queue and spawns off a
appthread.

appThread responds to :
-WM_COPYDATA: (Sent from clientApp)
takes a packet sent from client app and sends it off on the bus
****
You can put this in the main GUI thread providing the act of "sending it off to the bus"
consists of putting the message into a queue to be sent to the bus (no WriteFile
operations in the main GUI thread).
****
-QUEUE_READY: (Sent from mainloop)
gets notified from mainloop that it just put something in its queue.
the appthread will then empty the queue's contents, apply any filters on
it, and then send the packet off to its frontend app its responsible for.
****
This should be unnecessary. Either something is in the message queue or not. Note that
the message queue would have to have a lock on it (CRITICAL_SECTION, most likely) since,
while it is being processed, you have to prevent other threads from modifying it. This
lock ideally is set, a packet is removed, and the lock is released, no matter how many
packets are in the queue. But why do this in the main GUI thread? A secondary thread
with a semaphore would be simpler to implement, and less likely to have problems with race
conditions about items being put in the queue and the notifications being sent. For that
matter, why have a separate queue with notification messages; why not let the notification
message BE the queue entry?

The proposed solution seems a bit of a kludge; I always get suspicious when I see designs
like this because it usually means all the subtle race conditions have not been thought
out. Better to not have a separate data structure at all and just let the message carry
the data!
****

so is there a good model to implement this scheme? there's only going to
be one main loop, and multiple appthreads (one for each registering app)
each thread is going to be needing the ability to send and receive
windows messages, including wm_copydata. How do I create the appthreads
so that it can send/receive messages?
****
I have no idea what you mean by "one main loop". Do you mean "one main loop in the GUI
thread" or do you mean "a secondary thread that has a processing loop"? If the second,
using an I/O Completion Port as a queue makes a lot more sense than trying to manage a
secondary data structure with asynchronous notifications about changes in it. Key idea
here is that there is nothing really going on in the main GUI thread except GUI
operations; all interactions with the CANbus and with the client processes are managed in
separate threads. I would favor one thread per client plus at least one CANbus thread
(perhaps two, if you want asynchronous input and output)

Check out my essays on serial ports, use of I/O Completion Ports, and use of Semaphores,
if you haven't seen them already.
****

Each appthread should be an instance of a class that you derive from
CWinThread. That gives it the ability to process incoming windows
messages. You start each appthread by calling AfxBeginThread. To receive
WM_COPYDATA each of these threads will need a window. It can be invisible
if its only purpose is to receive messages. You don't have to do anything
to give the thread an ability to send/post messages: Any thread can do
that.
****
I would consider this a reasonable design, particularly if the client processes
communicate back via PostMessage or SendMessage(WM_COPYDATA); that way, a delay caused by
an individual process does not block all the other client processes
****


I initially wanted to have all of this in the backgournd (invisible)
however I now think its a good idea to at least have a small window
indicating that the backend is on and that the user can start up their
front end applications. I can also have the ability to display raw data
packets as well.
****
Take a look at my essay on dialog-based apps; I've already done this, and essentially the
sections on how to create a dialog-based app as a tray-icon app should be interesting
here, also Nish's contribution on how to avoid the "startup flash" (nice piece of work,
that)
****

Do all the display work in the main thread.

--
Scott McPhillips [VC++ MVP]


Since I just need a small dialog window , I'm using a dialog based mfc.
should I put the wm_canlib and appregister messages in the dialog's message
map? The handlers for these messages will then spawn off worker threads to
do what needs to get done.
****
Depends on whether or not you have bounded processing time with no possibility of hanging
while processing this message. If the processing time is not bounded, or there is a
distinct possibility of a hang of some sort, do this interaction in a separate thread

Generally, you will not spawn threads unless they are needed, and once spawned, a thread
will exist until, for example, its client process terminates.
*****

and for the appthreads, I'll extend a CWinThread that has an member that
I'll create that extends CWin. I will then put the the messages that i
specified above for appThread in the CWin derived class?
****
ON_MESSAGE or ON_REGISTERED_MESSAGE should be used. You should not even consider
ON_MESSAGE for interprocess messaging, but always use ON_REGISTERED_MESSAGE for
interprocess communication if you need a user-defined message for that purpose.

I have been done in so many times by WM_APP and WM_USER based messages that I now use
Registered Window Messages exclusively.
joe
****

is this correct?

Thanks,

Nick

Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.


Loading