WTL 错误





1.00/5 (1投票)
2000年6月1日

306031
已知的 WTL 和 ATL 错误
本文阐述了当前 WTL (3.1) 和 ATL (3.0) 实现中存在的一些错误。
最后修改时间:2000年11月29日
- WTL::CDC::DrawDragRect()
- WTL::CPropertyPageImpl::OnNotify()
- WTL::CPropertySheetImpl::OnCommand()
- WTL::CRichEdit::CharFromPos()
- WTL::DDX_TEXT 和 WTL::DDX_TEXT_LEN
- WTL::CCommandBarCtrlImpl::OnHookKeyDown()
- WTL::CFrameWindowImplBase::UpdateBarsPosition()
- WTL::CMDIWindow::GetStandardWindowMenu()
- ATL::CComPtr::IsEqualObject()
- ATL::IDispEventSimpleImpl::InvokeFromFuncInfo()
- ATL::CComContainedObject::QueryInterface()
- ATL::CAxHostWindow::GetDC()
AtlGDI.h, 行 2355-2414, 应该
void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast,
HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL)
...
if(hBrush == NULL)
hBrush = CDCHandle::GetHalftoneBrush();
...
...
// cleanup DC
if(hBrushOld != NULL)
SelectBrush(hBrushOld);
SelectClipRgn(NULL);
可能类似于
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; ... ... // cleanup DC if(hBrushOld != NULL) SelectBrush(hBrushOld); SelectClipRgn(NULL); if(NULL == hBrushIn) DeleteObject(hBrush); //Free our halftone brush DeleteObject(hRgnNew); DeleteObject(hRgnOutside); DeleteObject(hRgnInside); if (NULL != hRgnLast) DeleteObject(hRgnLast); if (NULL != hRgnUpdate) DeleteObject(hRgnUpdate);
一处存在六个内存泄漏。
该错误已由 Peter Datsichin 发布到 wtl@egroups.com
AtlDlgs.h, 行 2362, 应该
case PSN_WIZFINISH: lResult = !pT->OnWizardFinish();
可能类似于
case PSN_WIZFINISH: lResult = pT->OnWizardFinish();
如果查看 MS 关于 PSN_WIZFINISH 的文档,会说在 "comctl32.dll" 的 5.80 版本中,你可以返回一个窗口句柄来 1) 阻止向导完成,以及 2) 设置焦点到该函数返回的窗口句柄。 然而,WTL 否定了结果,因此返回 TRUE 允许向导完成,而返回 FALSE 则阻止它。 这样做就无法返回窗口句柄。
感谢 Simon-Pierre Cadieux。 见评论 "向导属性表 " 下面
AtlDlgs.h, 行 2146-2153, 应该
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
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;
}
可能类似于
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { 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; }
对于无模式向导属性表,一旦你点击“终止”按钮,该表单应该通过调用 DestroyWindow 来销毁。 然而,处理此事的 WTL 指令只检查 IDOK 和 IDCANCEL,而不是“终止按钮”的标识符
感谢 Simon-Pierre Cadieux。 见评论 "向导属性表 " 下面
AtlCtrls.h, 行 5807-5811 应该
int CharFromPos(POINT pt) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)); }
可能类似于
int CharFromPos(POINTL pt) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); }
该错误由 Richard L. Melton 发布
有关详细信息,请参阅 EM_CHARFROMPOS 的帮助
AtlDdx.h, 行 39-51 应该
#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; \ }
可能类似于
#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; \ }
使用 CString 版本的 DDX_Text 更好
AtlCtrlw.h 行 1639, 应该
AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
可能类似于
#ifndef _ATL_DLL AtlGetCommCtrlVersion(&dwMajor, &dwMinor); #else // Do it in some other way, there is no AtlGetCommCtrlVersion in atl.dll #endif
无论如何,建议不要使用 _ATL_DLL。
该错误由 Peter N Burgess 发布
AtlFrame.h 行 571-592, 应该
void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) { // resize toolbar 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; } // resize status bar 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; } }
可能类似于
void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) { // resize toolbar 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; } // resize status bar 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; // Force redraw of statusbar on top of possible vertical toolbar. if( dwStyles & CCS_VERT ) ::SetWindowPos(m_hWndStatusBar , HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE ); } }
否则你的垂直工具栏和 Rebar 将无法正确显示
该错误由 Carlos A. Ferraro Cavallini 发布
请参阅 评论 以下。
AtlFrame.h 行 1073-1087, 应该
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);
}
可能类似于
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); }
或只是:
static HMENU GetStandardWindowMenu(HMENU hMenu) { int nCount = ::GetMenuItemCount(hMenu); if(nCount == -1) return NULL; return ::GetSubMenu(hMenu, nCount - 2); }
类似作者忽略了除了英语之外还有其他语言。
该错误由 Toshihiro Sato 发布
请参阅 评论 以下。
AtlBase.h, 行 498-511, 652, 798 应该
bool IsEqualObject(IUnknown* pOther) { if (p == NULL && pOther == NULL) return true; // They are both NULL objects if (p == NULL || pOther == NULL) return false; // One is NULL the other is not CComPtr<IUnknown> punk1; CComPtr<IUnknown> punk2; p->QueryInterface(IID_IUnknown, (void**)&punk1); pOther->QueryInterface(IID_IUnknown, (void**)&punk2); return punk1 == punk2; }
可能类似于
bool IsEqualObject(IUnknown* pOther) { if (p == pOther) return true; // They are both NULL objects or the same object! if (p == NULL || pOther == NULL) return false; // One is NULL the other is not CComPtr<IUnknown> punk1; CComPtr<IUnknown> punk2; p->QueryInterface(IID_IUnknown, (void**)&punk1); pOther->QueryInterface(IID_IUnknown, (void**)&punk2); return punk1 == punk2; }
这不是一个真正的错误,但它会影响性能。
无论如何,你可以编写类似这样的代码
if (m_pObject == pOtherObject || m_pObject.IsEqualObject(pOtherObject))
{
// Do smth
}
AtlCom.h, 行 3731-3756 应该
//Helper for invoking the event
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;
}
可能类似于
//Helper for invoking the event
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, 行 2604, 应该
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) { HRESULT hr = OuterQueryInterface(iid, ppvObject); if (FAILED(hr) && _GetRawUnknown() != m_pOuterUnknown) hr = _InternalQueryInterface(iid, ppvObject); return hr; }
可能类似于
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) { return OuterQueryInterface(iid, ppvObject); }
CComContainedObject 不应该调用 _InternalQueryInterface()
该错误由 World Od ATL 发布
ATLHOST.H 行 1489, 应该
STDMETHOD(GetDC)(LPCRECT /*pRect*/, DWORD /*grfFlags*/, HDC* phDC) { if (phDC) return E_POINTER; *phDC = CWindowImpl<CAxHostWindow>::GetDC(); return S_OK; }
可能类似于
STDMETHOD(GetDC)(LPCRECT /*pRect*/, DWORD /*grfFlags*/, HDC* phDC) { if (!phDC) return E_POINTER; *phDC = CWindowImpl<CAxHostWindow>::GetDC(); return S_OK; }
无评论。 似乎是一个笔误
该错误由 Claus Michelsen 发布
一些有用的链接
Clipcode.com 和 Clipcode.com WTL 文档 + 示例IDevResource.Com WTL 错误和问题
World of ATL,错误和修复页面
DISCUSS.MICROSOFT.COM 邮件列表存档
microsoft.public.vc.atl 新闻组