Multithreaded ActiveX Controls Using ATL

Author

I will start developing the transmitter and during the development I will
tell how to improve it so it will meet normal industrial demands of a
multithreaded ActiveX control. I will also introduce the concept of Active
Objects, meaning objects running in their own thread. During this introduction I
will also give a Design Pattern/strategy for terminating Active Objects. I will
then continue with the receiver part, which is a bit more complicated because it
has to fire events from a worker thread. Actually there has to be done a lot of
work from the programmers side to make it work properly.


Creating the Control


First I create a usual ATL DLL project. I will not go into detail about that
because there is already tons of more or less good articles on this subject. At
this point it is very important to select the Merge Proxy/Stub code because we
later will be using marshal interface pointers. If we dont the proxy/stub will
have to be manually created and registered and that can introduce a lot of
problems at distribution time.


Next I create a usual full ActiveX control that is invisible at runtime. It
will support apartment threading because it must act as a single threaded
ActiveX control seen from languages like VB or Delphi. I doesnt need a window
because it is invisible at runtime, but it is put on anyway.



The Transmitter Part of the Control



The first task is to make the ActiveX Control able to send the data. I would like
the sending of data to be asynchronous so the data transmission dont interfere
with any graphical program that would make use of the control. This task could
easily be solved using a single threaded ActiveX control and asynchronous
IO-writing. But for introducing the concepts about Active Objects, critical
sections, and win32 events this practice is pretty good.
The ActiveX control has one method called TransmitByte that takes a single
character as argument and sends it to the com-port via the worker thread.
Having one method that takes only one simple argument is COM Automation in one
of its most simple forms. I will come back to TransmitByte later but before I
do that I will introduce the threading concept called Active Objects.


Active Objects or Object-Oriented Threading



Threads are normal C-functions started when calling the C-runtime library
functions _beginthread or _beginthreadex either explicitly
or implicitly (like in MFC) with the thread functions as an argument.
The _beginthread also takes a void* as argument.
The begin-methods creates a new stack and starts the method by calling it with
the void* as argument. As in the nature of void pointers the
void* can point to anything. This void* is used for
arguments to the thread function. The thread function then have to unpack the
data from the void* by typecasting it to something well known. The function is
running in its own thread until it returns.



struct rec{
double d;
char ch;
}

void f(void * r)
{
rec *tmp = (rec*) r;
loop ..
}

rec r; r.d = 3.1415; r.ch = 2;
_beginthread(f, 0, (void*)&r);
loop too


This approach isnt very object-oriented. If one wants a more object-oriented
approach to threading you can easily adopt to the scheme similar to one described
in
[1]. The idea in this article is to have class that can have instances
running in their own thread. In this article I will call the class CBasicThread.
CBasicThread has a virtual method called Command(). When creating a subclass
from this class that solves a problem in the user domain you overwrite this
method with you own Command() method and do your object oriented computing from
there. This is the concept of Active Objects. But how is the object activated.
Some way or another the _beginthread function must be called. It is not
possible to give an object as argument to _beginthread as it was with MFCs
AfxBeginThread. It is only possible to give a function and a void pointer as
argument. This extra void pointer will become important in a short while. The
start of the active object goes in two steps:



  1. Create the active object like an ordinary C++ object.


  2. Call a member function StartThread on the newly created class. This method
    will call _beginthread with the static member function RunProc and the self
    pointer this typecasted into void* and then it will terminate. The method
    RunProc is now running in its own thread and has as argument a void* to an
    object. It then typecasts the void* back into a CBasicThread* and calls the true
    member function CBasicThread::Run(). The Run() method works as a pseudo main()
    function because it initiates the thread of computing. It loops and for each
    iteration it calls Command() until some spooky halt condition is meet. The method then terminates and finally the thread stops executing

The definition of the CBasicThread looks like:


class CBasicThread
{
public:
static unsigned int __stdcall RunProc( void *pvoid );
CBasicThread(HWND & hWnd);
~CBasicThread();
void StartThread(int nPriority = THREAD_PRIORITY_NORMAL);
// starts the thread, call TerminateThread to stop the thread
// StartThread calls Run() that iterates until TerminateThread
// is called
// Use the virtual method Command to specify what you want to
// do during the iterations
void TerminateThread();
protected:
int Run();
virtual bool MayIContinue();
string m_threadname;
HANDLE m_workerThread;
private:
bool m_continue;
bool GetContinue();
void SetContinue(bool val);
_CritSec m_CritSec;
public:
virtual void PreCommand(){};
virtual void PostCommand(){};
virtual void Command() = 0; // the method to further bind. All
// parameters should
// be set using a new method or
};

The StartThread method looks like:


void CBasicThread::StartThread(int nPriority)
{
unsigned unThreadAddr;
m_workerThread = reinterpret_cast
(_beginthreadex(NULL, 0, RunProc,
this, 1, &unThreadAddr));
}

The program will have to be linked with the multithreaded versions of the C-runtime-libraries. This can be set in Project|Settings|C/C++|Code Generation|Use run-time Library. Remember there are different version for debug and release versions.
The static RunProc looks like:


unsigned int __stdcall CBasicThread::RunProc( void *pvoid )
{
CBasicThread *pThread = static_cast(pvoid);
return pThread->Run();
}

The Run method that is the Active part of the object and looks like:


int CBasicThread::Run()
{
PreCommand();
while (MayIContinue())
{
Command();
}
PostCommand();
return 0;
}

If you want to terminate the thread from the outside you have to ask it nicely and friendly to do so by itself like you would ask you grandmother to bake your favorite cookies. The alternative would be to kill it from the outside but by doing so you can easily loose resources so it is not a very good idea. So what you do is raising a flag so the method CBasicThread::MayIContinue will return false and the thread will terminate by running out. This is done from the outside (i.e. the main thread in the ActiveX control) by calling the method CBasicThread::TerminateThread:


void CBasicThread::TerminateThread()
{
SetContinue(false); // Terminates the thread by asking it to do it
// Waits until the thread is terminated
::WaitForSingleObject( m_workerThread, INFINITE );
}

As seen, the calling thread (i.e. the main thread) will wait until the thread terminates. So if the thread doesnt terminate we have an endless loop. We will investigate that later on.

Before and after the main loop the virtual methods CBasicThread::PreCommand and CBasicThread::PostCommand are called to do some subclass specific initialization and cleaning up.

When using subclasses of CBasicThread you have to be careful about the following:
Do not create the object on the stack (in a function) and the let that function run out of scope before the thread is stopped. It will lead to unexpected behavior because the object is destructed when it runs out of scope and the thread is still running.


The Active Transmitter Class (TransmitterThread)

The ActiveX control that we are creating will contain a subclass to the
CBasicThread class that is specific for sending data to the com-port. It will
specialize the abstract method Command so it will retrieve data from the
mainthread and send it to the com-port. The class definition looks like:


class CTransmitThread : public CBasicThread
{
public:
CTransmitThread(HWND & hWnd ,ts_queue & rqueue);
virtual ~CTransmitThread();
protected:
virtual bool MayIContinue();
virtual void PreCommand();
virtual void Command(void);
ts_queue & m_rqueue;
ComPort * m_pComPort;
};


Communication between Control and Active Object



The communication between the Active Object (worker thread) and the main thread
has to be threadsafe. The communication will be done through a STL queue of bytes.
The methods must be thread safe so we dont get any simultaneous reading and
writing. This can easily be done by specializing the STL adapter class queue by
using a critical section, which is the most simple and fastest synchronization
object on Win32 to protect the reading and writing inside the same process:


template
class ts_queue: public queue
{
typedef ThreadModel _ThreadModel;
typedef _ThreadModel::AutoCriticalSection _CritSec;
public:
ts_queue(){};
void put(const T in);
T get();
bool empty();
protected:
void Lock() {m_critsec.Lock();}
void Unlock() {m_critsec.Unlock();}
private:
_CritSec m_critsec;
};

template
bool ts_queue::empty()
{
bool tmp;
Lock();
tmp = queue::empty();
Unlock();
return tmp;
}

template
void ts_queue::put(const T in)
{
Lock();
push(in);
Unlock();
}

template
T ts_queue::get()
{
T tmp;
Lock();
tmp = front();
pop();
Unlock();
return tmp;
}


The ActiveX control creates the thread safe queue and hands a reference to the
Active Object through its constructor so they share this instance for
communication. The Active Object will implement the Command method like:


void CTransmitThread::Command(void)
{
if (!m_rqueue.empty())
{
unsigned char ch;
ch = m_rqueue.get();
m_pComPort->Transmit(ch);
}
}


The pointer to the comport-object is initialized in the constructor for the
thread, but this might as well have been in the PreCommand method. I will not go
into detail about the comport object except it opens a com-port for serial
communication at 2400 Baud and it implements a method called ComPort::Transmit
that will write a byte to the com-port. We will investigate the com-port object
later on when talking about the Active Receiver Object.


Adding a Method to the ActiveX Control

The ATL Method Wizard is used for adding a method TransmitByte to the control.
In IDL it looks like:


[id(1), helpstring(“method TransmitByte”)] HRESULT TransmitByte([in] unsigned char ch);

TransmitByte takes a single character as argument and send it to the com-port
via the worker thread. Having one method that takes only one simple argument is
COM in one of its most simple forms (Automation). The implementation of
TransmitByte looks like:


STDMETHODIMP CTransmit::TransmitByte(unsigned char ch)
{
// TODO: Add your implementation code here
m_tsqueue.put(ch);
return S_OK;
}

It sends the byte to the Active Transmitter Object through the thread safe queue. Both the threadsafe queue and the Active Transmitter Object are instances belonging to the ActiveX control. The constructor for the control will initialize the Active Transmitter Object with the threadsafe queue, like:


CComm():
m_tt(m_tsqueue)
{
m_bWindowOnly = TRUE;
}

The control will also implement the two methods FinalConstruct and FinalDestroy that is virtual methods on CComControl (one of the superclasses for our control) that is called respectively right after the total construction and right before total destruction of the ActiveX control. In FinalConstruct the worker thread will be started depending on the state of the container (we will dig more into that later). In the destructor the thread will be stopped. Stopping the thread is not as simple as it may seem and I will discuss it in great detail.
FinalConstruct and FinalRelease are used instead of the normal C++ constructor and destructor. This is because both the constructor and the destructor arent good targets for the operations because we cannot be sure of the state of the member variables in this phase of construction/destruction. In this case the finals are responsible for the lifetime of the Active Transmitter Object, like:


HRESULT CComm::FinalConstruct( )
{
BOOL runmode = FALSE;
HRESULT hres = GetAmbientUserMode(runmode);
if (!SUCCEEDED(hres))
runmode = TRUE
if (runmode)
{
m_tt.StartThread();
}
return S_OK;
}

void CComm::FinalRelease( )
{
BOOL runmode = FALSE;
HRESULT hres = GetAmbientUserMode(runmode);
if (!SUCCEEDED(hres))
runmode = TRUE
if (runmode)
{
m_tt-> TerminateThread(); // this method will wait for the worker thread to terminate
}
}

The two final-methods use the method GetAmbientUserMode to determine whether or
not the ActiveX control is in design mode or run mode. Design mode is when you
are designing your GUI using VB. VB (like many other containers) loads and
instansiates the control also in design mode. It would be stupid to start the
threads in design mode so we try to avoid this, but as many other MS stuff this
doesnt work. The moral is: do not rely on GetAmbientUserMode to determine the
state of the container. Use some other technique to do that. This will be
investigated at the end.


Behavior and Termination

At this point we can create a VB program that uses the control. It should have
one Edit box where the property MultiLine is set to TRUE and it should hold one
instance of the ActiveX Control (You will have to browse for the DLL).

At design time the form could look like:

The code for the VB program would look like:


Private Sub Text1_KeyPress(KeyAscii As Integer)
Comm1.TransmitByte (KeyAscii)
End Sub

At runtime the VB program would look like:

As you can see the control is invisible at runtime. This is a registry setting
that can be manipulated through the MiscStatus entry in the reg-script. Finding
the right bits to set is not a simple task and this is an effort in itself. When
changes are made to the MiscStatus you have to recompile your VB program to make
the changes shine through.
The problem about the current implementation of the ActiveX control is that the
Active Transmitter Object waits actively on input from container (VB program),
meaning it loops and for each iteration it checks some halt condition. This
active waiting will slow down execution of the VB program (and actually the
whole desktop). It will feel like rubber bands are attached to all windows.
The active waiting happens in the virtual Command method. In the following I
will solve the problem in two tempi. First I will do the obvious one using Win32
events on behalf of loosing the ability to control the termination of the Active
Object. In the second step I will state the Design Pattern/ strategy for
termination of Active Objects by introducing Terminators


Adding Support for Win32 Events

The rubber band problem can easily be solved using theWin32 synchronization
mechanism: Events. The reader on the thread safe queue will wait passively for
someone to put data in the queue using the Win32 ::WaitForSingleObject. The event
that something has arrived will be signaled from the put method on the thread
safe queue, like:


template
class ts_queue: public queue
{
typedef ThreadModel _ThreadModel;
typedef _ThreadModel::AutoCriticalSection _CritSec;
public:
ts_queue():m_event(false, true){}; //manually reset
void put(const T in);
T get();
bool empty();
bool waitNonEmpty();
void Lock() {m_critsec.Lock();}
void Unlock() {m_critsec.Unlock();}
private:
_CritSec m_critsec;
CEvent m_event;
};

template
bool ts_queue::waitNonEmpty()
{
Lock();
if (!empty())
{
Unlock();
return true;
}
m_event.ResetEvent();
Unlock();
::WaitForSingleObject(m_event, INFINITE);
return true;
}

template
void ts_queue::put(const T in)
{
Lock();
push(in);
m_event.SetEvent();
Unlock();
}

The Active Transmitter Object will have to call waitNonEmpty() instead of
calling the empty() method actively. This method will execute (passively)
until a character is put into the queue. The method Command() now looks like:


void CTransmitThread::Command(void)
{
if (m_rqueue.waitNonEmpty() && (MayIContinue()))
{
m_pComPort->Transmit(m_rqueue.get());
}
}

The CEvent class used in the threadsafe queue is not a part of ATL but snapped
and modified from the MFC library. It simply encapsulates the Win32 event
mechanism into a class (see the source).


class CEvent : public CSyncObject
{

// Constructor
public:
CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE,
LPCTSTR lpszNAme = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);

// Operations
public:
BOOL SetEvent();
BOOL PulseEvent();
BOOL ResetEvent();
BOOL Unlock();

// Implementation
public:
virtual ~CEvent();
};

Using the CEvent and calling WaitForSingleObject will make termination of the
thread awkward. Termination can only happen right after a character has been
sent to the Active Transmitter Object. This is not a good strategy for
termination. In the following I will introduce a strategy for termination that
is widely applicable.


The Terminator

The following has nothing to do with Arnold Schwartzenegger and it is not
science fiction. It is based on a true story but there might be a sequal. The
idea of the Terminator is that each time an active object has to wait for some
kind of Win32 object using a ::WaitForSingleObject it will use the terminator
instead. The Active Objects will at startup time sign up as an observer for the
termination event. When the ActiveX control is terminating it will ask the
terminator to set the terminate event and all Active Objects that is passively
waiting for an event to happen will at this time be interrupted and can then
terminate in an ordered manner. Instead of calling ::WaitForSingleObject the
Active Objects will call Terminator::Wait with the event as argument. The Wait()
method will then call ::WaitForMultipleObjects instead of ::WaitForSingleObject
with both the event from the Active Object and the terminate event as argument.
The Terminator class looks like:


class Terminator
{
private:
CEvent m_termEvent;
bool is_terminating;
typedef CComMultiThreadModel ThreadModel;
typedef ThreadModel _ThreadModel;
typedef _ThreadModel::AutoCriticalSection _CritSec;

_CritSec m_signUpCS;
vector m_runningThreads; // protected by m_signUpCS
public:
void TerminateAll();
bool TerminatingAll();
bool Wait(CSyncObject * pSyncObj); // True if pSync is now Locked
// False Means terminated or timed out
bool Wait(HANDLE eventHandle); // True if pSync is now Locked
void SignUp(HANDLE hThread);
public: // singleton
static Terminator* Instance();
LONG Release();
static LONG m_cRef;
protected:// Singleton
Terminator();
~Terminator();
private: // Singleton
static Terminator* m_instance;

};

The implementation of the Terminator::Wait() method looks like:


bool Terminator::Wait(HANDLE eventHandle)
{
HANDLE h[2];
h[0] = eventHandle;
h[1] = m_termEvent.m_hObject;
DWORD lockVal;
lockVal = ::WaitForMultipleObjects(2, h, false, INFINITE);
return lockVal == WAIT_OBJECT_0;
}

And the Terminator::TerminateAll that
is used by the control to terminate the control looks like:


void Terminator::TerminateAll()
{
is_terminating = true;
m_termEvent.SetEvent();

vector::iterator i;
for (i=m_runningThreads.begin(); i

The Active Objects sign up during their initialization using Terminator::SignUp. This concept is fairly simple and applicable for many similar situations. In this case the Terminator is a singleton and can only be reached through the static method Terminator::Instance(). This ensures us that there is only one terminator in the game at any time. Other schemes can off cause be adopted.
The thread safe queue will now change its implementation of waitNonEmpty to:


template
bool ts_queue::waitNonEmpty()
{
Lock();
if (!empty())
{
Unlock();
return true;
}
m_event.ResetEvent();
Unlock();
Terminator * m_pTerm = Terminator::Instance();
bool tmp = m_pTerm->Wait(&m_event);
m_pTerm->Release();
m_event.ResetEvent();
return tmp;
}

This small modification ensures there will be no rubberbands in the GUI and that
the active object is terminated in a descent way. This finishes the transmitter
part of the control.


The Receiver Part of the Control

The second task is to make the ActiveX control able to receive data from the
com-port. My solution will both use Active Objects (threading) and the Terminator
to do asynchronous communication between the VB program and the com-port. When a
byte arrives at the com-port it will be sent to the VB program using the COM
mechanism: Events. This mechanism is not to be confused with the Win32
synchronization objects: Events. This scheme is not very efficient because an
event has to be fired each time a byte arrives. Other more efficient schemes
could have been adopted but for the sake of illustration is it sufficient.
The Receiver part of the control is more tricky than the transmitter because the
events have to been fired from a worker thread inside an Active Receiver Object.
I will here describe a mechanism that uses marshalled interface pointer to the
control
[6] [7].


Firing Events

First the control must be enabled for firing events This is done in three tempi
as described in
[2]: Defining the event interface, using the ATL proxy generator,
and implementing a bit of code. This is not as easy as in MFC and VB but it is
well described and very fast to do.

First: Defining IDL

First I define the event that is to be fired in IDL. I call it Received. The
definition looks like:


library COMMUNICATIONLib
{
importlib(“stdole32.tlb”);
importlib(“stdole2.tlb”);

[
uuid(974da5c0-b1f8-11d1-aabb-006097636471),
helpstring(“Event interface for ReceiveCtl”)
]
dispinterface _CommEvents
{
properties:
methods:
[id(1)] void Received([in]unsigned char ch);
};

[
uuid(3BC3F4C1-B80C-11D1-AABD-006097636471),
helpstring(“Comm Class”)
]
coclass Comm
{
[default] interface IComm;
[default, source] dispinterface _CommEvents;
};
};

It is important to remember to have the definition of the event disp-interface
inside the library definition otherwise the MIDL compiler wont generate the
right code. The interface could also have been defined outside and just
referenced inside the library. The event interface does not have to be a pure
dispatch interface (dispinterface) but can also be a pure custom interface. VB
(from 6.0 and forwards) doesnt care as long as it not dual. After running the
MIDL compiler the ATL proxy generator is used.

Second: The ATL Proxy Generator

The code for the events can be generated by the Proxy Generator. Using the Proxy
generator (as described in the article The Proxy Generator in VC++ 5.0
(VC++ 6.0 looks a bit different):

>

The generated proxy is now in the file CPCommunication.h

Third: Changing the CComm class definition

Add the interface and map changes. Include CPCommunication.h.


// Comm.h : Declaration of the Ccomm
.
#include “CPCommunication.h” // for events

/////////////////////////////////////////////////////////////////////////////
// CComm
class ATL_NO_VTABLE CComm :
public CComObjectRootEx,
public CComCoClass,
public CComControl,
public IDispatchImpl,
public IProvideClassInfo2Impl<&CLSID_Comm, &DIID__CommEvents, &LIBID_COMMUNICATIONLib>, //DIID__CommEvents added for events
public IPersistStreamInitImpl,
public IPersistStorageImpl,
public IQuickActivateImpl,
public IOleControlImpl,
public IOleObjectImpl,
public IOleInPlaceActiveObjectImpl,
public IViewObjectExImpl,
public IOleInPlaceObjectWindowlessImpl,
public IDataObjectImpl,
public ISupportErrorInfo,
public CProxy_CommEvents, // for events
public IConnectionPointContainerImpl,
public IPropertyNotifySinkCP
// public ISpecifyPropertyPagesImpl
{
public:
CComm():
.
..
BEGIN_COM_MAP(CComm)

COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()

BEGIN_CONNECTION_POINT_MAP(CComm)
CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
CONNECTION_POINT_ENTRY(DIID__CommEvents) // comm events
END_CONNECTION_POINT_MAP()

The control can now fire events by calling the method Fire_Received defined on the control (through multiple inheritance). The event have to be fired from the a worker thread so lets create the Active Receiver Object that will act as the worker thread for reading the bytes from the port.

The Active Receiver Object

The active Receiver object is quite similar to the Active Transmitter Object. I
also subclasses the CBasicThread class. The Command() method looks like:


void CReceiveThread::Command(void)
{
unsigned char ch;
while (m_pComPort->Receive(ch))
{
m_ts_receive_queue.put(ch);
}
}

The ComPort::Receive waits passively using the Terminator::Wait mechanism as in
CTransmitThread on an incomming byte from the com-port. This ensures good
termination and no rubber-band effect in the GUI.

Conclusion

In this article I have described how to create a control that can handle the
demands for a small efficient industrial strength multithreaded ActiveX control
using ATL (3.0). I have shown how Active Objects and Terminators can be used
efficiently to handle the lifetime and behavior of objects running in their own
thread. I have also shown how to use COM to syncronize between a worker thread
and the main thread (the thread in the main apartment). The solution works
perfectly on both WinNT 4.0 (sp1) and win95 with at least DCOM95 installed.

Good Luck!

In a future article I hope to show how to extend the idea of components so the
communication part of the threads can become a polymorphic COM object so it can
easily be replaced with a COM object that uses i.e. sockets or DCOM.


Acknowledgement


I would like to thank Thomas Sonne Olesen, DTI, CIT, for introducing me to
Terminators and Ove Frost Sxrensen, Kommunedata, for introducing me to
multithreaded ActiveX controls using MFC. I would also like to thank my
girlfriend Lise for being patient in the process of writing this article.
And remember COM IS LOVE!


References


  1. MSJ 1997 Volume 12, More First Aid for the Thread Impaired: Cool Ways to
    Take Advantage of Multithreading by Russell Weisz


  2. ATL Tutorial: Step 5: Adding an Event to Your Control


  3. MS Knowledge Base (Q157437): FIREEV.EXE Fires Events from Second Thread


  4. MSDN News, Ask Dr Gui #37, Can You Use a Second Thread for Sutures

  5. MSDN News, May 15, 1997, Events: From an ATL Server to a Visual Basic Sink

  6. Microsoft Press, Inside COM, Dale Rogersen

  7. Addison Wesley, Essential COM, Don Box

  8. Addison Wesley, Effective COM, Chris Sells, Tim Ewald, Keith Brown, Don Box

Download demo project – 33 KB

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read