(Not to alarm anyone, but) ATL can be stupid, sometimes

by Michael S. Kaplan, published on 2004/12/12 10:08 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2004/12/12/280196.aspx

Let me start by saying I think ATL is cool. It kicks ass, it takes names. But even the most incredible technology can do things that do not achieve brilliance 100% of the time....

This bit of code had been buried in ATL for a long time (the part I am calling stupid is marked in red).

static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)_AtlWinModule.ExtractCreateWndData();
    ATLASSERT(pThis != NULL);
    pThis->m_hWnd = hWnd;

    // Initialize the thunk. This was allocated in CContainedWindowT::Create,
    // so failure is unexpected here.

    pThis->m_thunk.Init(WindowProc, pThis);
    WNDPROC pProc = pThis->m_thunk.GetWNDPROC();
    WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
#ifdef _DEBUG
    // check if somebody has subclassed us already since we discard it
    if(pOldProc != StartWindowProc)
      ATLTRACE(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));
    pOldProc; // avoid unused warning
    return pProc(hWnd, uMsg, wParam, lParam);

I think WTL might have the same assert but I am hoping it does not. :-)

This StartWindowProc function is the initial WNDPROC, which is quickly replaced by the actual WNDPROC, right here in this code. After that, it is never called again. I guess the assert is there to check for when the developer has been subclassing it themselves (to warn them that they did an oopsie).

But its still pretty weird from my point of view. After all, the StartWindowProc WNDPROC is assigned to the window class and clearly since we are in StartWindowProc the message is getting through. So who cares if it was subclassed? Well clearly ATL does. But if ATL wants to have an architecture that throws away their initial WNDPROC and want to warn the developer that their subclass may never get messages, then they should stick that in their documentation, not throw asserts. 

From my point of view, the point of view of the developer who wrote MSLU (which has the job of wrapping all of the WNDPROCs and DLGPROCs that are created so that it can convert to and from Unicode not only when the application send messages but when messages are sent to the application), this is truly a bad assert. In fact, if you are using MSLU and the debug version of ATL, then you are guaranteed to have this assert fire once for each window created. Of course since (a) every call is properly routed by MSLU and (b) its never going to be called again, the fact that the vaue returned is not the same doesn't seem to matter.

In the MSLU case, if ATL bothered to check whether GetWindowLongPtr would return the same WNDPROC just assigned to it, they would get back a different values again. Because MSLU has to wrap this WNDPROC, too. I guess I should be glad that they do not bother to do this, or else there would be twice as many asserts. Maybe they could use that fact as a debug technique to decide whether they even should assert at all here?

Anyway, I regularly get email and newsgroup postings from people using MSLU who hit the assert and wonder what they might be doing wrong (or alternately, why MSLU appears to be so damn broken -- depending on the personality, mood, and temperment of the one asking the question).

Which indirectly points to what may be one of the key definitions of stupidity I have -- something responsible for wasting my time, needlessly. :-)

# . on 12 Dec 2004 10:46 AM:

Why do people still use crap technologies like this on "NEW" applications? Especially having eggs in one basket when its not cross platform either.

# michkap on 12 Dec 2004 10:50 AM:

Not sure which technology you mean here (MSLU or ATL).

MSLU does not require application changes, it just lets your apps support Unicode, even if you have customers who refuse to upgrade from Win9x.

ATL is getting bigger all the time, but there is still a lot of use to it.

People spend a lot of time talking about cross-platform, but the number of people who actually <b>do</b> cross platform work is pretty small. Most people write for one, using the skills and tools they know....

# Michael Kaplan on 17 Dec 2004 1:39 PM:

That updated assert would look something like:

// check if somebody has subclassed us already since we discard it
if(pOldProc != StartWindowProc)
if(pProc == (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC))
ATLTRACE(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));

go to newer or older post, or back to index or month or day