QQ2009-2012内部数据CTXStringW解析

前一阵子用系统的BSTR构造函数SysAllocString来模拟CTXStringW,但是结果是不稳定。什么是不稳定?就是有时候可以,有时候崩溃。用过FineIP早期版本的童鞋都知道FineIP是第一个可以在框内显示的辅助工具,而FineIP超级稳定,几乎没出现过崩溃的现象,几乎和QQ融为一体。这是为神马呢?

首先我们要了解BSTR,BSTR是BasicString的简写,是一种COM通用的字符串结构。

简介下BSTR的结构:

一个INT32来表示文本长度,一个wchar_t是宽字符串数据,用结构体表示为:

1
2
3
4
5
typedef struct MyBSTR
{
    DWORD dwLen;//表示长度
    wchar_t strBuff[4100];//宽文本字符串数据
};

比如:L"我是1颗白菜",相对应的文本长度应该是12,那么Len就等于12,下面的StrBuff就对应是L"我是1颗白菜"。

下面是模仿系统的SysAllocString函数生成一个BSTR的源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
BSTR AllocBasicString(const wchar_t * lpSrc)
{
    if(lpSrc == NULL) return NULL;
    BYTE * bBuffer = new BYTE[4+(wcslen(lpSrc)+1)*2];
    if(bBuffer == NULL) return NULL;
    DWORD dwLenth = wcslen(lpSrc)+1;
    memmove(bBuffer,&dwLenth,4);
    wcscpy((wchar_t *)(bBuffer+4),lpSrc);
    return BSTR(bBuffer+4);
}

为神马返回的是buf1+4而不是直接buf1?因为BSTR其实表面上他就是wchar_t *,程序在找字符串长度时直接寻找前方的数据以提高效率,而这个4正是一个DWORD的长度。

你可能会奇怪为什么我花这么大段落来写BSTR,其实CTXStringW就是BSTR,下面我们就来研究下CTXStringW与BSTR:

我先说下CTXStringW的结构:

一个为0的DWORD,一个为3的DWORD,两个DWORD表示长度,一个wchar_t是宽字符串数据,用结构体表示为:

1
2
3
4
5
6
7
8
typedef struct CTXBSTR
{
    DWORD pMemMan;//内存管理器,我们不需要,直接写0
    DWORD dwCount;//这里是提醒QQ是否回收内存,如果是0肯定会回收引起崩溃,小于等于2也不稳定,我们就填3
    DWORD dwLen2;//这里不管是不是长度都无所谓了,因为QQ的返回字符串都没这个
    DWORD dwLen;//这里是宽字符的长度,wcslen返回一个数值就行
    wchar_t strBuff[4100];
} TXStr,* pTXStr;

我相信上面你如果看懂的话你就发现,其实CTXStringW就是BSTR,前面三个DWORD仅仅是为了防止QQ回收内存导致崩溃,差别并不大,这就是为什么有时直接传SysAllocString函数生成的字符串有时可以通过的原因。

所以就直接将CTXStringW理解为BSTR即可

比如:L"我是1颗白菜",pMemMan=0,dwCount=3,相对应的文本长度应该是6,那么dwLen=12,下面的strBuff就对应是L"我是1颗白菜"。

下面是模仿生成CTXStringW的函数源码,返回值我就依旧是用BSTR了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//定义CTXStringW为BSTR
typedef BSTR CTXStringW;

CTXStringW AllocTXString(const wchar_t * lpSrc)
{
    if(lpSrc == NULL) return NULL;
    BYTE * bBuffer = new BYTE[16+(wcslen(lpSrc)+1)*2];
    if(bBuffer == NULL) return NULL;
    DWORD dwZero = 0;
    DWORD dwCount = 3;
    DWORD dwLenth = wcslen(lpSrc)+1;
    memmove(bBuffer+0*4,&dwZero,4);
    memmove(bBuffer+1*4,&dwCount,4);
    memmove(bBuffer+2*4,&dwLenth,4);
    memmove(bBuffer+3*4,&dwLenth,4);
    wcscpy((wchar_t *)(bBuffer+4*4),lpSrc);
    return CTXStringW(bBuffer+16);
}

PS:以上就是CTXStringW的分析,可能有出入之处,敬请大牛指出,同时也希望越来越多的童鞋加入QQ显IP软件的行列一同探究哦~

部分资料参考自互联网、山野哥(QQFun/QQYoo作者)、Morning(FinePlus/FineIP作者)之经验。