I'm in the process of porting a C++/WTL project from Visual Studio 2005 to VS 2008. One of the project configurations is a unit-testing build, which defines the preprocessor symbol UNIT_TEST.
In order to get my WTL classes into my test harness, I made a CFakeWindow
class that stubs all the CWindow methods. Then in my stdafx.h file, I do this right below the import of atlwin.h (which defines the CWindow class):
#ifdef UNIT_TEST
#include "fakewindow.h"
#define CWindow CFakeWindow
#endif
My window classes then look like this:
class CAboutDialog :
public CDialogImpl< CAboutDialog, CWindow >
, public CDialogResize< CAboutDialog >
{
// class definition omitted...
};
This works great in VS 2005. The problem is that in VS 2008, the methods from the original CWindow class are getting called, instead of the CFakeWindow class. This of course causes the tests to fail, because CWindow
is sprinkled with ATLASSERT(::IsWindow(m_hWnd))
.
When I step through the code in the debugger, I see that the CAboutDialog class is inheriting from CDialogImpl<CAboutDialog, CFakeWindow>
. Yet when I call a method on CAboutDialog
(e.g. EndDialog(code)
), the CWindow
method is getting called.
Is this a bug in VS 2008, or was my conditional template inheritance technique an abomination that VS 2005 allowed but VS 2008 "fixed"? Is there a work-around, or do I need to consider a different technique to unit-test WTL classes? I really like this technique, because it lets me get WTL classes into a test harness without mucking about with the WTL library.
Edit: As noted in the response to Conal, below, the preprocessor output shows that my class is inheriting from CFakeWindow:
class CAboutDialog :
public CDialogImpl<CAboutDialog, CFakeWindow >
, public CDialogResize< CAboutDialog >
...
And as stated above, when I step through the code in the debugger, CAboutDialog is shown in the locals window as inheriting from CFakeWindow.
Edit 2: As per Conal's advice, I stepped through the disassembly, and the code is supposedly calling the CFakeWindow method, but the CWindow method is what is actually called.
if ( wID == IDCANCEL )
00434898 movzx edx,word ptr [ebp+8]
0043489C cmp edx,2
0043489F jne CAboutDialog::OnCloseCmd+90h (4348B0h)
{
EndDialog( wID ) ;
004348A1 movzx eax,word ptr [ebp+8]
004348A5 push eax
004348A6 mov ecx,dword ptr [ebp-10h]
004348A9 call ATL::CDialogImpl<CAboutDialog,ATL::CFakeWindow>::EndDialog (40D102h)
}
else
004348AE jmp CAboutDialog::OnCloseCmd+9Ah (4348BAh)
{
EndDialog(IDOK);
004348B0 push 1
004348B2 mov ecx,dword ptr [ebp-10h]
004348B5 call ATL::CDialogImpl<CAboutDialog,ATL::CFakeWindow>::EndDialog (40D102h)
I'm starting to lean more toward a bug in the VC++ 2008 debugger.