This article illustrates bugs that are present in the current WTL (3.1) & ATL (3.0) implementation.
Last Modified : 11/29/2000
AtlGDI.h, line 2355-2414, instead of:
void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast,
HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL)
...
if(hBrush == NULL)
hBrush = CDCHandle::GetHalftoneBrush();
...
...
if(hBrushOld != NULL)
SelectBrush(hBrushOld);
SelectClipRgn(NULL);
It can be something like
void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,
SIZE sizeLast, HBRUSH hBrushIn = NULL,
HBRUSH hBrushLast = NULL)
...
if(hBrushIn == NULL)
hBrush = CDCHandle::GetHalftoneBrush();
else
hBrush = hBrushIn;
...
...
if(hBrushOld != NULL)
SelectBrush(hBrushOld);
SelectClipRgn(NULL);
if(NULL == hBrushIn)
DeleteObject(hBrush);
DeleteObject(hRgnNew);
DeleteObject(hRgnOutside);
DeleteObject(hRgnInside);
if (NULL != hRgnLast)
DeleteObject(hRgnLast);
if (NULL != hRgnUpdate)
DeleteObject(hRgnUpdate);
Six memory leaks in one place.
The bug has been posted to wtl@egroups.com by Peter Datsichin
AtlDlgs.h, line 2362, instead of:
case PSN_WIZFINISH:
lResult = !pT->OnWizardFinish();
It can be something like
case PSN_WIZFINISH:
lResult = pT->OnWizardFinish();
If one looks at the MS documentation on PSN_WIZFINISH it is said that with version 5.80 of "comctl32.dll" you can return a window handle to 1) prevent the wizard from finishing and 2) set the focus on the window handle returned by the function. However, WTL negates the result so that returning TRUE allow the wizard to finish while returning FALSE prevent it. By doing so it is not possible to return a window handle.
Thanks to Simon-Pierre Cadieux. See comment "Wizard Property Sheet " below
AtlDlgs.h, line 2146-2153, instead of:
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& )
{
LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK ||
LOWORD(wParam) == IDCANCEL) &&
((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL))
DestroyWindow();
return lRet;
}
It can be something like
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& )
{
LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
if(HIWORD(wParam) == BN_CLICKED && ((m_psh.dwFlags & PSH_MODELESS) != 0) &&
((LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) ||
#if (_WIN32_IE >= 0x0500) && defined(PSH_WIZARD_LITE)
((m_psh.dwFlags & (PSH_WIZARD | PSH_WIZARD97 | PSH_WIZARD_LITE)) != 0)) &&
#elif (_WIN32_IE >= 0x0400) && defined(PSH_WIZARD97)
((m_psh.dwFlags & (PSH_WIZARD | PSH_WIZARD97)) != 0)) &&
#else
((m_psh.dwFlags & PSH_WIZARD) != 0)) &&
#endif
(GetActivePage() == NULL))
DestroyWindow();
return lRet;
}
For modeless wizard property sheet, once you clicked on the "Terminate" button the sheet should be destroyed by calling DestroyWindow. However the WTL instructions that handle that only check for IDOK and IDCANCEL not the identifier of the "Terminate Button"
Thanks to Simon-Pierre Cadieux. See comment "Wizard Property Sheet " below
AtlCtrls.h, Lines 5807-5811 instead of:
int CharFromPos(POINT pt) const
{
ATLASSERT(::IsWindow(m_hWnd));
return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0,
MAKELPARAM(pt.x, pt.y));
}
It can be something like
int CharFromPos(POINTL pt) const
{
ATLASSERT(::IsWindow(m_hWnd));
return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0,
(LPARAM)&pt);
}
The bug was published by Richard L. Melton
See help on EM_CHARFROMPOS for details
AtlDdx.h, lines 39-51 instead of:
#define DDX_TEXT(nID, var) \
if(nCtlID == (UINT)-1 || nCtlID == nID) \
{ \
if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
return FALSE; \
}
#define DDX_TEXT_LEN(nID, var, len) \
if(nCtlID == (UINT)-1 || nCtlID == nID) \
{ \
if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \
return FALSE; \
}
It can be something like
#define DDX_TEXT(nID, var) \
if(nCtlID == (UINT)-1 || nCtlID == nID) \
{ \
if(!DDX_Text(nID, var, sizeof(var)/sizeof(var[0]), \
bSaveAndValidate)) \
return FALSE; \
}
#define DDX_TEXT_LEN(nID, var, len) \
if(nCtlID == (UINT)-1 || nCtlID == nID) \
{ \
if(!DDX_Text(nID, var, sizeof(var)/sizeof(var[0]), \
bSaveAndValidate, TRUE, len)) \
return FALSE; \
}
It is much better to use CString version of DDX_Text
AtlCtrlw.h Line 1639, instead of:
AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
It can be something like
#ifndef _ATL_DLL
AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
#else
#endif
It is recommended to not use _ATL_DLL anyway.
The bug was published by Peter N Burgess
AtlFrame.h Lines 571-592, instead of:
void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
{
if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar,
GWL_STYLE) & WS_VISIBLE))
{
if(bResizeBars)
::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
RECT rectTB;
::GetWindowRect(m_hWndToolBar, &rectTB);
rect.top += rectTB.bottom - rectTB.top;
}
if(m_hWndStatusBar != NULL &&
((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))
{
if(bResizeBars)
::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
RECT rectSB;
::GetWindowRect(m_hWndStatusBar, &rectSB);
rect.bottom -= rectSB.bottom - rectSB.top;
}
}
It can be something like
void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
{
if(m_hWndToolBar != NULL &&
((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))
{
if(bResizeBars)
::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
RECT rectTB;
::GetWindowRect(m_hWndToolBar, &rectTB);
if( dwStyles & CCS_VERT )
rect.left += rectTB.right - rectTB.left;
else
rect.top += rectTB.bottom - rectTB.top;
}
if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar,
GWL_STYLE) & WS_VISIBLE))
{
if(bResizeBars)
::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
RECT rectSB;
::GetWindowRect(m_hWndStatusBar, &rectSB);
rect.bottom -= rectSB.bottom - rectSB.top;
if( dwStyles & CCS_VERT )
::SetWindowPos(m_hWndStatusBar , HWND_TOP, 0, 0, 0, 0,
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
}
}
Otherwise your vertical toolbars+rebars will not showing up properly
The bug was published by Carlos A. Ferraro Cavallini
See comment below.
AtlFrame.h Lines 1073-1087, instead of:
static HMENU GetStandardWindowMenu(HMENU hMenu)
{
int nCount = ::GetMenuItemCount(hMenu);
if(nCount == -1)
return NULL;
int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
if(nLen == 0)
return NULL;
LPTSTR lpszText = (LPTSTR)_alloca((nLen + 1) * sizeof(TCHAR));
if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
return NULL;
if(lstrcmp(lpszText, _T("&Window")))
return NULL;
return ::GetSubMenu(hMenu, nCount - 2);
}
It can be something like
static HMENU GetStandardWindowMenu(HMENU hMenu)
{
int nCount = ::GetMenuItemCount(hMenu);
if(nCount == -1)
return NULL;
int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
if(nLen == 0)
return NULL;
LPTSTR lpszText = (LPTSTR)_alloca((nLen + 1) * sizeof(TCHAR));
if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
return NULL;
if(lstrcmp(lpszText, LOCALE_INDEPENDED_STRING))
return NULL;
return ::GetSubMenu(hMenu, nCount - 2);
}
or just
static HMENU GetStandardWindowMenu(HMENU hMenu)
{
int nCount = ::GetMenuItemCount(hMenu);
if(nCount == -1)
return NULL;
return ::GetSubMenu(hMenu, nCount - 2);
}
Similar that the author has overlooked that there are other languages except for English.
The bug was published by Toshihiro Sato
See comment below.
AtlBase.h, lines 498-511, 652, 798 instead of:
bool IsEqualObject(IUnknown* pOther)
{
if (p == NULL && pOther == NULL)
return true;
if (p == NULL || pOther == NULL)
return false;
CComPtr<IUnknown> punk1;
CComPtr<IUnknown> punk2;
p->QueryInterface(IID_IUnknown, (void**)&punk1);
pOther->QueryInterface(IID_IUnknown, (void**)&punk2);
return punk1 == punk2;
}
It can be something like
bool IsEqualObject(IUnknown* pOther)
{
if (p == pOther)
return true;
if (p == NULL || pOther == NULL)
return false;
CComPtr<IUnknown> punk1;
CComPtr<IUnknown> punk2;
p->QueryInterface(IID_IUnknown, (void**)&punk1);
pOther->QueryInterface(IID_IUnknown, (void**)&punk2);
return punk1 == punk2;
}
It's not a real bug, but it hits the performance.
Anyway you can code something like this:
if (m_pObject == pOtherObject || m_pObject.IsEqualObject(pOtherObject))
{
}
AtlCom.h, lines 3731-3756 instead of:
HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info,
DISPPARAMS* pdispparams, VARIANT* pvarResult)
{
T* pT = static_cast<T*>(this);
VARIANTARG** pVarArgs = info.nParams ?
(VARIANTARG**)alloca(sizeof(VARIANTARG*)*info.nParams) : 0;
for (int i=0; i<info.nParams; i++)
pVarArgs[i] = &pdispparams->rgvarg[info.nParams - i - 1];
CComStdCallThunk<T> thunk;
thunk.Init(pEvent, pT);
CComVariant tmpResult;
if (pvarResult == NULL)
pvarResult = &tmpResult;
HRESULT hr = DispCallFunc(
&thunk,
0,
info.cc,
info.vtReturn,
info.nParams,
info.pVarTypes,
pVarArgs,
pvarResult);
ATLASSERT(SUCCEEDED(hr));
return hr;
}
It can be something like
HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(),
_ATL_FUNC_INFO& info, DISPPARAMS* pdispparams,
VARIANT* pvarResult)
{
T* pT = static_cast<T*>(this);
VARIANTARG** pVarArgs = info.nParams ?
(VARIANTARG**)alloca(sizeof(VARIANTARG*)*info.nParams) : 0;
VARTYPE * pVarTypes = info.nParams ?
(VARTYPE *)alloca(sizeof(VARTYPE)*info.nParams) : 0;
for (int i=0; i<info.nParams; i++)
{
pVarArgs[i] = &pdispparams->rgvarg[info.nParams - i - 1];
pVarTypes[i] = info.pVarTypes[info.nParams - i - 1];
}
CComStdCallThunk<T> thunk;
thunk.Init(pEvent, pT);
CComVariant tmpResult;
if (pvarResult == NULL)
pvarResult = &tmpResult;
HRESULT hr = DispCallFunc(
&thunk,
0,
info.cc,
info.vtReturn,
info.nParams,
pVarTypes,
pVarArgs,
pvarResult);
ATLASSERT(SUCCEEDED(hr));
return hr;
}
Atlcom.h, Line 2604, instead of:
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
HRESULT hr = OuterQueryInterface(iid, ppvObject);
if (FAILED(hr) && _GetRawUnknown() != m_pOuterUnknown)
hr = _InternalQueryInterface(iid, ppvObject);
return hr;
}
It can be something like
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
return OuterQueryInterface(iid, ppvObject);
}
CComContainedObject shouldn't call _InternalQueryInterface()
The bug was published by World Od ATL
ATLHOST.H Line 1489, instead of:
STDMETHOD(GetDC)(LPCRECT , DWORD , HDC* phDC)
{
if (phDC)
return E_POINTER;
*phDC = CWindowImpl<CAxHostWindow>::GetDC();
return S_OK;
}
It can be something like
STDMETHOD(GetDC)(LPCRECT , DWORD , HDC* phDC)
{
if (!phDC)
return E_POINTER;
*phDC = CWindowImpl<CAxHostWindow>::GetDC();
return S_OK;
}
No comments. Seems to be a mistype
The bug was published by Claus Michelsen
Some useful links
Clipcode.com and
Clipcode.com WTL Doc + SamplesIDevResource.Com WTL Bugs and IssuesWorld of ATL, bugs and fixes pageDISCUSS.MICROSOFT.COM Mailing List Archivesmicrosoft.public.vc.atl newsgroup