Sep 032014
 

Issue

Recently had a customer who was facing this issue. His code looked as follows (assuming COM’s initialized) which apparently is trying to setup an ActiveX control…

HWND hWnd = CreateWindow(_T(ATLAXWIN_CLASS),
_T(“SysMon”),
WS_CHILD,
0, 10, 100, 200,
hwndParent,
NULL,
hInstance,
NULL);

As soon as above code executes the application crashes.

image

Why loading ActiveX failed?

Callstack for the crash looks as follows…

ConsoleApplication1.exe!ATL::CComPolyObject<ATL::CAxHostWindow>::CComPolyObject<ATL::CAxHostWindow>
ConsoleApplication1.exe!ATL::CComCreator<ATL::CComPolyObject<ATL::CAxHostWindow> >::CreateInstance
ConsoleApplication1.exe!AtlAxCreateControlLicEx
ConsoleApplication1.exe!AtlAxCreateControlLic
ConsoleApplication1.exe!ATL::AtlAxWindowProc
user32.dll!UserCallWinProcCheckWow
user32.dll!DispatchClientMessage
user32.dll!__fnINLPCREATESTRUCT
ntdll.dll!KiUserCallbackDispatch    Unknown
user32.dll!ZwUserCreateWindowEx    Unknown
user32.dll!VerNtUserCreateWindowEx
user32.dll!CreateWindowInternal
user32.dll!CreateWindowExW
ConsoleApplication1.exe!wmain
ConsoleApplication1.exe!__tmainCRTStartup
ConsoleApplication1.exe!wmainCRTStartup
kernel32.dll!BaseThreadInitThunk
ntdll.dll!RtlUserThreadStart

 

Autos debug window showed following…

image

Resolution

The highlighted elements gave ample hint. This is a console application with no ATL boilerplate code generated by project wizard for this project. Ideally ATL requires a global CComModule instance to initialize itself. This is how the CComModule constructor looks like…

CComModule()
{
// Should have only one instance of a class
// derived from CComModule in a project.
ATLASSERT(_pModule == NULL);
<span style="background-color: #ffff00;">_pModule = this;</span>
#if !defined(_ATL_NATIVE_INITIALIZATION)
#pragma warning(push)  // disable 4483
#pragma warning(disable:4483)
using namespace __identifier("<AtlImplementationDetails>");
#pragma warning(pop)  // disable 4483
ATLASSERT(ComModuleInitialized == false);
// If ComModuleHelper.Module == NULL it mean that DllMain has not been called, so we assume CComModule lives in
// an exe and not in a dll
if (ComModuleHelper.Module != NULL)
{
ATLASSERT(ComModuleHelper.Module == this);
_DllMain(ComModuleHelper.Instance, DLL_PROCESS_ATTACH, NULL, ComModuleHelper.ObjectMap, ComModuleHelper.LibraryId);
}
ComModuleInitialized = true;
#endif
}

This function further initializes _pModule instance to point to this global instance of ours eventually. So after we declare CComModule global instance this is how _pAtlModule (it points to our  global instance) will look after instantiation of our global CComModule…

image

Crash resolved.

Sep 192013
 

Long back we used to have an ActiveX test container called TstCon, which was used for debugging our ActiveX controls.

I went looking for the container and found TstCon in the samples folder, Ideally it will be the following sample folder…

root\AllVCLanguageSamples\C++\MFC\ole\TstCon

More of why TstCon was moved out of the standard tools that ships with Visual Studio is explained here…

http://blogs.msdn.com/b/vcblog/archive/2010/03/18/activex-test-container-application-is-still-available.aspx

In VS2008 and VS2010 the samples will be found in the sample folder under
VsInstallDir\Samples\1033\

Sep 062013
 

Was working with a customer yesterday who was having this issue of GetDlgItem failing to return a valid window handle for an ActiveX control placed on a dialog. The ActiveX control is visible though but curiously the handle was always showing up as NULL.

While debugging saw this particular line in the Visual Studio 2010 output window…

image

Hmm interesting. Why is the control saying I want to be windowless. Customer never mentioned he wants a windowless control.

So when creating an ActiveX control the wizard provides a checkbox which says the following…

image

When the above checkbox is checked the wizard adds the following line of code into your ActiveX control’s constructor…

image

In my customer’s case this was the reason for GetDlgItem not returning a valid window object for the ActiveX control.

Another way this problem can manifest is when you turn off m_bWindowOnly in your activex control class. This variable will be off if you are creating a windowless control.

In short I would say: always keep an eye on the visual studio output window. 🙂

Mar 172011
 

Recently a customer of mine faced this issue. So he had an ActiveX control and when displaying the ActiveX control in browser a string is displayed right in the middle of the control: “ATL 9.0”.

So this issue happens because you didn’t override CComControlBase::OnDraw  function. The default code for CComControlBase::OnDraw looks like the following…

HRESULT CComControlBase::YourClassName::OnDraw(_In_ ATL_DRAWINFO& di)
{
  ::SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
  LPCTSTR pszText = _T("ATL ") _T(_ATL_VER_RBLD); // "ATL 9.0"
  ::TextOut(di.hdcDraw,
            di.prcBounds->left + (di.prcBounds->right - di.prcBounds->left) / 2,
            di.prcBounds->top + (di.prcBounds->bottom - di.prcBounds->top) / 2,
            pszText,
            lstrlen(pszText)); 
   return S_OK;
}

MSDN documentation for CComControlBase::OnDraw function confirms this behavior. Quote…

The wizard’s default OnDraw draws a rectangle with the label “ATL 8.0”.

The solution for this is to override CComControlBase::OnDraw function in your derived class and provide your own drawing or just return S_OK.