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,这也算是一个
好方法.