WTL中CListViewCtrlT的GetItemText的实现分析

以下函数来自WTL中文件:

Wtl-90_4035\Include\atlctrls.h


原文没有任何注释,尽量给每一行代码都增加注释:

#ifndef _ATL_NO_COM
BOOL GetItemText(int nItem, int nSubItem, BSTR& bstrText) const
{
     USES_CONVERSION; // 字符串转换中的临时缓冲的释放管理
     ATLASSERT(::IsWindow(m_hWnd)); // 有效窗口,不要随便给我一个
     ATLASSERT(bstrText == NULL); // 必须给我空的!我会处理好返回给你,记住你自己释放!
     LVITEM lvi = { 0 }; // 结构体初始化
     lvi.iSubItem = nSubItem;

     LPTSTR lpstrText = NULL; // 初始化必要的,如果不是NULL,下面的算法将无法进行
     int nRes = 0; // 返回长度,注意这是在尝试去读取,可能会很大,很大怎么办?看下面
     for(int nLen = 256; ; nLen *= 2) // 每次增加一倍,总有一次足够容纳你
     {
          ATLTRY(lpstrText = new TCHAR[nLen]); // 异常捕获,我可以失败,但我不能死
          if(lpstrText == NULL) // 内存分配的成功是没有保证
               break;
          lpstrText[0] = NULL; // 内存分配成功是没初始化的,记住,这不是C++11
          lvi.cchTextMax = nLen; // 给你缓冲,你用吧
          lvi.pszText = lpstrText;
          // 进入windows了,你管不着了
          nRes  = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);
          if(nRes < nLen - 1) // 记住上面的说明,如果读取的长度比传入的空间小,读取完了,否则回到for
               break;
          delete [] lpstrText; // 下一次尝试读取前,删除这时的内存
          lpstrText = NULL; // 防止非法访问,看下面的判断
     }

     if(lpstrText != NULL)
     {
          if(nRes != 0) // 实际长度不是0
               bstrText = ::SysAllocString(T2OLE(lpstrText)); // 从系统中重新分配内存
          delete [] lpstrText; // 释放当前块
     }

     return (bstrText != NULL) ? TRUE : FALSE; // 不空就读取成功
}
#endif // !_ATL_NO_COM


这个函数对开发人员的要求:

  1. 必须牢牢记住BSTR等的用法
  2. 必须理解GetItemText的用法
  3. 内存管理意识



你可能感兴趣的:(开发工具)