Constructing hidden windows in ATL

Comment on this article

Archive with project

Getting timer messages into an ATL object isn't all that evident. If you create a full control and it remains invisible in runtime, it has no windows handle, so you can't use the classical ::SetTimer(hWnd,...) to get the timer messages.

The trick is to create another ATL window object that does absolutely nothing but create a window and get these messages. Then have the timer message handler call whatever method you want in your "real" ATL object.

The extra ATL window class looks like the following. I place it in the same file as the main ATL class, but before it, adding a forward class declaration for the main class, of course. In the constructor it takes a pointer to the ATL object that needs timer ticks.

// fullctrl.h
class CWinHidden : 
  public CWindowImpl<CWinHidden, CWindow, CNullTraits>
    {
      BEGIN_MSG_MAP(CWinHidden)
        MESSAGE_HANDLER(WM_TIMER, OnTimer)
      END_MSG_MAP()
      public:
        CWinHidden(Cfullctrl* pFullCtrl) : m_pFullCtrl(pFullCtrl) {};

      public:
        LRESULT OnTimer(UINT, WPARAM, LPARAM, BOOL&);
      private:
        Cfullctrl*   m_pFullCtrl;
	};

The OnTimer handler does nothing but call the "real" ATL object. In this case I call the OnTimer() handler, but actually it could be anything you like.

// fullctrl.cpp

LRESULT CWinHidden::OnTimer(UINT uMsg, WPARAM wParam, 
    LPARAM lParam, BOOL& bHandled)
{
  m_pFullCtrl->OnTimer(uMsg, wParam, lParam, bHandled);
  return 0;
}

Caveat:

Now you have two objects running message loops here. If this is all in an STA, there should be no problems, but if you're using more advanced threading models, I can very well imagine that having the one object (CWinHidden) just call right into the other (Cfullctrl) is not entirely safe. If so, you would need to use mutexes and/or critical sections to secure things. 

Comment on this article

TOP