从CString设置LPSTR

时间:2013-09-19 13:16:27

标签: c++ mfc tooltip cstring

我正在尝试在MFC对话框上设置工具提示。我有从字符串资源中读取工具提示的代码,我试图将其修改为不从资源中读取而是构成工具提示。

我的实现导致垃圾显示为工具提示而不是我想要的字符串。此外,它在从调试器运行时导致崩溃,但在直接运行可执行文件时却没有(我确定存在缓冲区损坏或类似情况)

以下是相关的代码:

BOOL CPreviewDlg::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
    ASSERT(pNMHDR->code == TTN_NEEDTEXT);

    TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR;

    if (!(pTTT->uFlags & TTF_IDISHWND))
        return FALSE;

    UINT_PTR hWnd = pNMHDR->idFrom;
    // idFrom is actually the HWND of the tool
    UINT nID = (UINT)(WORD)::GetDlgCtrlID((HWND)hWnd);

    CString sDlgItemText;
    (UINT)(WORD)::GetDlgItemText(this->GetSafeHwnd(), nID, sDlgItemText.GetBufferSetLength(50), 50);
    sDlgItemText.ReleaseBuffer();

    if(sDlgItemText.IsEmpty())
        sDlgItemText = _T("Unnamed");

    CString sToolTip = _T("");
    sToolTip.Format(_T("%s \n This is the %s control. Here we can put its description."), sDlgItemText, sDlgItemText);

    pTTT->lpszText = sToolTip.GetBufferSetLength(sToolTip.GetLength());/* MAKEINTRESOURCE(nID);*/
    pTTT->hinst = AfxGetInstanceHandle();
    sToolTip.ReleaseBuffer();
    *pResult = 0;

    // bring the tooltip window above other popup windows
    ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
        SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);

    return TRUE;    // message was handled
}

我很确定错误是我试图设置pTTT->lpszText(而不是MAKEINTRESOURCE)的地方我认为我没有从CString设置LPSTR的正确方法

CString sDlgItemText;
(UINT)(WORD)::GetDlgItemText(this->GetSafeHwnd(), nID, sDlgItemText.GetBufferSetLength(50), 50);
sDlgItemText.ReleaseBuffer();

if(sDlgItemText.IsEmpty())
    sDlgItemText = _T("Unnamed");

CString sToolTip = _T("");
sToolTip.Format(_T("%s \n This is the %s control. Here we can put its description."), sDlgItemText, sDlgItemText);

pTTT->lpszText = sToolTip.GetBufferSetLength(sToolTip.GetLength());/* MAKEINTRESOURCE(nID);*/

2 个答案:

答案 0 :(得分:1)

我认为你的问题是退出函数后pTTT->lpszText中的指针值不再有效。

如果您的文字长度少于80个字符,或者您可以截断工具提示,则可以使用

lstrcpy(pTTT->szText, sToolTip);

否则,您需要使sToolTip成为全局变量或CPreviewDlg类的成员变量。

参考:MSDN article

答案 1 :(得分:0)

根问题是您从sToolTip.m_pData)处理程序返回局部变量(OnToolTipText的地址。当控件离开通知处理程序时,sToolTip超出范围并且析构函数运行,留下垃圾。

要解决此问题,您有两个选择:

  1. 将工具提示文本复制到TOOLTIPTEXT::szText[]数组。
  2. 延长您返回的缓冲区的生命周期,以便在系统需要时可用。生命周期不需要比封闭实体(在这种情况下为对话框)更长,因此对话框的类成员将会这样做。
  3. 与您的问题无关:在为TOOLTIPTEXT::lpszText成员分配指针时,您应该使用const_cast而不是调用CString::GetBuffer[SetLength]()TOOLTIPTEXT结构用于两个方向,用于设置和检索工具提示信息。因此,成员不能被声明const,即使它们是。它可能看起来很尴尬但你宁愿做以下事情:

    pTTT->lpszText = const_cast<LPTSTR>(static_cast<LPCTSTR>(sToolTip));