65.9K
CodeProject 正在变化。 阅读更多。
Home

WTL 错误

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (1投票)

2000年6月1日

viewsIcon

306031

已知的 WTL 和 ATL 错误

本文阐述了当前 WTL (3.1) 和 ATL (3.0) 实现中存在的一些错误。

最后修改时间:2000年11月29日




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.comClipcode.com WTL 文档 + 示例
IDevResource.Com WTL 错误和问题
World of ATL,错误和修复页面
DISCUSS.MICROSOFT.COM 邮件列表存档
microsoft.public.vc.atl 新闻组

© . All rights reserved.