在 CComboBoxEx 和 ReleaseBuffer 中插入和项目

Posted

技术标签:

【中文标题】在 CComboBoxEx 和 ReleaseBuffer 中插入和项目【英文标题】:Inserting and item into CComboBoxEx and ReleaseBuffer 【发布时间】:2021-10-15 18:19:05 【问题描述】:

代码:

m_cbReminderInterval.ResetContent();
for (int i = 1; i <= m_iMaxReminderInterval; i++)

    COMBOBOXEXITEM cmbItem = ;
    CString strNumber;
    strNumber.Format(_T("%d"), i);

    cmbItem.mask = CBEIF_TEXT;
    cmbItem.iItem = static_cast<INT_PTR>(i) - 1;
    cmbItem.pszText = strNumber.GetBuffer(_MAX_PATH);
    strNumber.ReleaseBuffer(); // TODO: When should I release the buffer - NOW or AFTER the InsertItem call?

    m_cbReminderInterval.InsertItem(&cmbItem);

我的问题是:

在这种情况下使用GetString 而不是GetBuffer 更好吗?我看到的唯一问题是pszTextLPWSTRGetString 返回LPCWSTR。如果我应该继续使用GetBuffer,那么它应该什么时候真正发布呢?在InsertItem 通话之前还是之后?

【问题讨论】:

【参考方案1】:

您会一遍又一遍地看到 Windows API 中的一个常见模式:const-正确的结构比看起来可能的结构要少。毫无疑问,其中一些是疏忽,但不是这个:COMBOBOXEXITEM 用于插入和查询项目的数据。

pszText 成员的文档部分暗示了这一点:

指向包含或接收项目文本的字符缓冲区的指针。如果正在检索文本信息,则必须将此成员设置为将接收文本的字符缓冲区的地址。

遗憾的是,文档中省略了合同的第二部分。设置项的文本时,控件会复制传入的字符串,并且既不会获得指向数据的所有权,也不会修改它。换句话说:当使用COMBOBOXEXITEM结构插入一个项目时,可以假设所有的指针都指向const

接下来,传递来自GetString()的指针是完全有效的:

for (int i = 1; i <= m_iMaxReminderInterval; i++)

    COMBOBOXEXITEM cmbItem = ;
    CString strNumber;
    strNumber.Format(_T("%d"), i);

    cmbItem.mask = CBEIF_TEXT;
    cmbItem.iItem = static_cast<INT_PTR>(i) - 1;
    cmbItem.pszText = const_cast<TCHAR*>(strNumber.GetString());

    m_cbReminderInterval.InsertItem(&cmbItem);

【讨论】:

也感谢您的回答和澄清。一个问题......在底层结构中,成员变量设计为LPWSTR pszText。我应该使用LPWSTR 作为铸造类型吗?由于我使用此代码构建 32 位和 64 位。 这并不完全正确。 COMBOBOXEXITEM 实际上并不存在。它映射到WA 变体,具体取决于是否定义了UNICODE 预处理器符号。同样,CString 实际上并不存在。它映射到CStringACStringW,这取决于一些更复杂的预处理器符号评估。由于您对任一类型都使用通用文本映射,因此 TCHAR* 是正确且兼容的类型。就个人而言,我会使用CStringWCOMBOBOXEXITEMW,以及对应的字符串类型wchar_t*【参考方案2】:

根据CSimpleStringT::GetBuffer

如果你使用GetBuffer返回的指针来改变字符串内容,你必须在使用任何其他CSimpleStringT成员方法之前调用ReleaseBuffer

你没有修改字符串,所以你不需要调用ReleaseBuffer

但正如你所说,最好使用GetString,至少你表明你不打算修改它。

【讨论】:

谢谢。因此,简单地使用:cmbItem.pszText = strNumber.GetString(); 并删除strNumber.ReleaseBuffer() 应该是可以接受的。我会试试的。 @AndrewTruckle 请注意,ReleaseBuffer 只能在 GetBuffer 之后调用。 GetString 只是给你指向 CString 缓冲区的指针,仅此而已。

以上是关于在 CComboBoxEx 和 ReleaseBuffer 中插入和项目的主要内容,如果未能解决你的问题,请参考以下文章

MFC CComboBoxEx 图标更新问题

用图标计算 CComboBoxEx 的最大下拉宽度

Mfc CComboBoxEx - 如何更改背景颜色

CImagelist 基本用法

MFC-CImagelist图像列表控件

如何在 MFC 自定义控件类中挂钩控件关闭