因为项目需求,要在CListCtrl中加上排序小图标,Google到博文http://blog.csdn.net/liujiannanit125/article/details/6249039,感谢博主的奉献。不过实际使用中出现一个问题,加上这段代码后,经常出现写入内存错误,时有时无,很不好找原因。怀疑是pHdrCtrl->SetItem( i, &hdi );语句写入时出错,注释后故障以旧,多次调试后发现注释pHdrCtrl->GetItem(i, &hdi);语句后,故障消失。为什么读取信息出现写入内存错误呢,百思不得其解。
再次仔细阅读msdn的说明和例子后恍然大悟,GetItem的第二个参数即是输入参数又是输出参数,调用前必需在hdi.mask中指定获取哪些参数。获取标题文字的代码如下:
HDITEM hdi;
enum { sizeOfBuffer = 256 };
TCHAR lpBuffer[sizeOfBuffer];
hdi.mask = HDI_TEXT;
hdi.pszText = lpBuffer;
hdi.cchTextMax = sizeOfBuffer;
问题就出在这里,原文中没有初始化 hdi.mask 而直接调用 GetItem,hdi.mask 的内容是随机的,碰巧包含HDI_TEXT,就会对 hdi.pszText 写入标题文字,hdi.pszText 也是随机的,可能是非法地址,于是出现有时能用,有时报错的情况。下面有意写一段错误代码,果然每次都出错。
hdi.mask = HDI_TEXT;
hdi.pszText = (LPTSTR)1;
hdi.cchTextMax = 100;
m_myHeaderCtrl.GetItem(i, &hdi);
问题找到了,新写代码与下,经测试没有发现问题。
const CString sorts[] = { NULL, NULL, L"number", L"CONVERT(name USING GBK)", L"sex", L"birthday",
L"age", L"regday", L"scanday", L"importday", L"scancount", L"note" }; // 第一列是ID列, 第二列是序号列,不排序。
LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
// 自定义图标排序箭头样式
CHeaderCtrl* pHdrCtrl = GetHeaderCtrl();
int n = pHdrCtrl->GetItemCount();
ASSERT( n == sizeof(sorts)/sizeof(CString) ); // 列数与数组一致
m_strOrderby = sorts[ phdr->iItem ];
if( m_strOrderby.IsEmpty() ) // 没有排序
return;
HDITEM hdi;
for( int i = 0; i < n; i++ )
{
hdi.mask = HDI_IMAGE | HDI_FORMAT; // 读取排序箭头图标状态,必需指定
pHdrCtrl->GetItem(i, &hdi);
if( i == phdr->iItem )
{
if( hdi.fmt & HDF_IMAGE ) // 已经排序,改变升降序。
{
hdi.iImage = 1 - hdi.iImage;
}
else
{
hdi.iImage = 0;
hdi.fmt |= HDF_IMAGE | HDF_BITMAP_ON_RIGHT;
}
if( hdi.iImage )
m_strOrderby += " DESC";
}
else
{
hdi.mask = HDI_FORMAT;
hdi.fmt &= ~HDF_IMAGE & ~HDF_BITMAP_ON_RIGHT;
}
pHdrCtrl->SetItem( i, &hdi );
}