激烈振动

Visit My MSN Space

导航

ATL组件中文路径注册问题(转载)

ATL组件注册的一个很糟糕的BUG,以至于需要通过修改ATL源码来解决。记录在此,方便下次重装机器后使用。

  我曾用ATL写过一个COM组件(MBCS下编译),如果安装在中文路径下的话,注册就会失败.
  为什么会失败?
  打开ATL的源文件statreg.h,可以找到函数BOOL AddString(LPCOLESTR lpsz),他被
组件的UpdateRegistry所调用,他又调用了BOOL AddChar(const TCHAR* pch).问题就
出现在这两个函数中。请看:
  BOOL AddString(LPCOLESTR lpsz)
  {
   USES_CONVERSION;
   LPCTSTR lpszT = OLE2CT(lpsz);
   while (*lpszT)
   {
    AddChar(lpszT);
    lpszT++; // note! @1
   }
   return TRUE;
  }
  BOOL AddChar(const TCHAR* pch)
  {
   if (nPos == nSize) // realloc @3
   {
    nSize *= 2;
    p = (LPTSTR) CoTaskMemRealloc(p, nSize*sizeof(TCHAR));
   }
   p[nPos++] = *pch;
#ifndef _UNICODE
   if (IsDBCSLeadByte(*pch))
    p[nPos++] = *(pch + 1); file://note! @2
#endif
   return TRUE;
  }
 当我们不是使用UNICODE时,如果遇到一个汉字的话,标注@2行识别整个汉字,存入缓冲区.但是pch变量仍然指向
汉字的第一个字节,返回到@1行时,lpszT++后指向了该汉字的第二个字节!以后又把该汉字的第二字节当成一个独立的字
符再次处理一遍.所以就产生了乱码.(致使组件注册的信息有一部分是错误的)
 怎么解决?
 由上面的分析,很容易得到解决的办法:
  BOOL AddString(LPCOLESTR lpsz)
  {
   USES_CONVERSION;
   LPCTSTR lpszT = OLE2CT(lpsz);
   while (*lpszT)
   {
    AddChar(lpszT);
    lpszT++; 
   }
   return TRUE;
  }
/*******************************************************************
 * This function cause some error in hanzi.
 *  Modified by L.C. ,Nov 12th,2001
 *******************************************************************/
/********************************************************************
  BOOL AddChar(const TCHAR* pch)
 ********************************************************************/
  BOOL AddChar(const TCHAR* &pch) file://we'll modify the pch value
  {
   if (nPos == nSize) // realloc
   {
    nSize *= 2;
    p = (LPTSTR) CoTaskMemRealloc(p, nSize*sizeof(TCHAR));
   }
   p[nPos++] = *pch;
#ifndef _UNICODE
   if (IsDBCSLeadByte(*pch))
/*******************************************************************
    p[nPos++] = *(pch + 1); 
********************************************************************/
    p[nPos++] = *( ++ pch);
#endif
   return TRUE;
  }
 还有什么错误?
 请观察@3行,如果阅读一下这个类的源代码(180行开始),很明显会有缓冲区溢出的危险:
在非UNICODE情况下,nPos要加两次,而进入这段代码时有可能是nPos=nSize-1.如果是这样,恐怕程序的
会有一些无法预测的行为(虽然几率很小:在 rgs文件中出现大段中文的可能性不多)。修改实际上比较
容易,将if (nPos == nSize) 变为if (nPos == nSize-1)即可。(当然有很多别的方法)
 结论
 如果你的组件有可能出现在中文路径下的话(使用MBCS),建议你在编译时使用_ATL_STATIC_REGISTRY
编译,并且在编译前修改ATL中相关的代码(或自己写注册函数)。否则现有的ATL.DLL会坏了你的好事.
 修改现有的类库是很危险的事情。因为他们的调用关系太复杂了.不过,如果他里面有BUG,这也算是一个
好方法.

posted on 2005-09-07 17:11  vibration  阅读(1611)  评论(0编辑  收藏  举报