从 CString 设置 LPSTR

Posted

技术标签:

【中文标题】从 CString 设置 LPSTR【英文标题】:Set LPSTR from CString 【发布时间】:2013-09-19 13:16:26 【问题描述】:

我正在尝试在 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);*/

【问题讨论】:

TOOLTIPTEXT 中的 lpszText 是 LPTSTR,而不是 LPSTR,因此它必须与 CString 兼容。 (CString 是 16 位中的 8 位,具体取决于您的项目设置,LPTSTR 也是如此。)所以错误一定在其他地方。 【参考方案1】:

我认为您的问题是,一旦您退出函数,pTTT->lpszText 中的指针值将不再有效。

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

lstrcpy(pTTT->szText, sToolTip);

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

参考:MSDN article。

【讨论】:

【参考方案2】:

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

要解决这个问题,您有 2 个选项:

    将工具提示文本复制到TOOLTIPTEXT::szText[] 数组。 增加返回的缓冲区的生命周期,以便在系统需要时可用。生命周期不需要比封闭实体(本例中的对话框)长,因此对话框的类成员就可以了。

与您的问题无关:分配指向TOOLTIPTEXT::lpszText 成员的指针时,您应该使用const_cast 而不是调用CString::GetBuffer[SetLength]()TOOLTIPTEXT 结构用于两个方向,以设置和检索工具提示信息。因此,成员不能被声明为const,即使它们是。它可能看起来很尴尬,但您更愿意执行以下操作:

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

【讨论】:

以上是关于从 CString 设置 LPSTR的主要内容,如果未能解决你的问题,请参考以下文章

从 CString 引用中获取 CString?

从 Cstring 中删除 \x

无法从 char 构造 CString

从 CString 中提取浮点数

CString 设置宽字符有啥作用

如何从字符数组创建 CString?