|
下载源代码 1、我的两个群都很热,有很多人加入,这样,不用很快,群里的人就达到了上限200人了,就不能再让新的人加入. 对于这两个问题,我是这么的解决的. 1、当人数达到上限时,我就让群里的人都在群的名字前面加上一些特别的符号,比如:@%#%&^*,总之就是一些一般人不会用在自己群的名字的符号吧,以这些符号作为标志,识别哪些人是长期没有在群里发言的人.把这个改名的要求发在群的公告里,对于那些长期没有上线的人,当然看不到群的公告,也就不会改群的名片了.我以这些符号作为标志,清除那些长期不上线的人,留些空间,让新人能加进来. 这两种的做法都是把人给T出群里,但是在实际操作中却很麻烦了. 对于第一种情况,有些人把那个特别的符号放在群名字中的某个地方,比如,要求把@加在名字前面,有个名字叫天使,本来按照要求,改名后就变为@天使,但这个人却很有个性,他把名字改为天@使,对于这些人,当然可以不管三七二十一,一律当成是没有改名,把他T出群外啦.但是考虑到这个人还是有看到公告的,还是让他留下来吧,但这样就苦了我这个当管理员的啦,在200个人里面,一个个的看哪个人的名字不符合公告的要求.人这么多,把我都看到眼花聊乱的了.既要把人T走,又不好T错了.做这样的事,也真是费功夫的. 对于第二种情况,也是一样的,因为聊天信息的那个窗口里,只能看到这个人的名字和QQ号,为了把这个人T了,还得在群设置里,一个个人的去对,找那个QQ号,实在是痛苦,都是数字,要很细心一个个的核对,一不小心就把这个号给漏了过去,又得重新找一遍了,有好几次,我都是找了三次以上才把那个QQ号才找出来.为此,我想做一个工具,只要输入QQ号,就可以把人T走了.最初,我是想抓取QQ把群里的人T走时的数据包来分析一下.知道了这个数据包消息的格式后,我就可以仿造一个消息,直接的向QQ服务器发过去,就可以把人给T了.我用工具把T人时的数据包抓取一下,全部都是乱码的.因为QQ的消息格式并没有公开,把以分析起来真的是头痛了,都无从下手了,只好把这个想法放弃了.我又想了一下,既然我不能发这样的数据包,那就直接让QQ自己发这个包吧.为了要让QQ把T人的包给发出去,就得从QQ自己的界面入手,输入QQ号后,能在群设置里直接的定位到要T的QQ号,这样就不用人工的去找这个QQ号,省却了去找这个QQ号的痛苦了. 二、问题的分析
EnumWindows(EnumWindowsProc,0);//枚举所有的窗口
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
TCHAR buff[1000];
int buffsize(100),nPosition(-1);
HWND hQQWnd=NULL;
::GetWindowText(hwnd,buff,buffsize);
if (strlen(buff)<1)
return TRUE;
CString str(buff);
nPosition=str.Find(_T("群设置")); //这里设置要找的窗口名
if(nPosition!=-1)
EnumChildWindows(hwnd,ChildWndProc,0);//继续找子窗口
return TRUE;
}
//枚举包含有syslistview32的类型为#32770的窗口的句柄
BOOL CALLBACK ChildWndProc(HWND hwnd, LPARAM lParam)
{
LPTSTR lptstr;
HGLOBAL hglb=NULL;
char className[CLASS_SIZE];
if (GetClassName(hwnd,className,CLASS_SIZE)==0)
return TRUE;
CString str(className);
HWND hChild = GetWindow(hwnd, GW_CHILD);
if (GetClassName(hChild,className,CLASS_SIZE)==0)
return TRUE;
CString strChildName(className);
//顶层窗口下有四个类型都为”#32770”的dialog,其中只有其中一个
//才是包括有成员列表的
while (str != _T("#32770") || strChildName != _T("SysListView32"))
{
HWND h1= GetNextWindow(hwnd, GW_HWNDNEXT);
GetClassName(h1,className,CLASS_SIZE);
str = className;
hwnd = h1;
hChild = GetWindow(hwnd, GW_CHILD);
if (GetClassName(hChild,className,CLASS_SIZE)==0)
return TRUE;
strChildName =className;
}
EnumChildWindows(hwnd,DeleWndProc,0);//在包含syslistview的dialog中继续找
}
找到了包含有syslistview的窗口后,就继续找syslistview了,然后可以向它发送命令消息了.这是整个程序的关键部分,先把代码给出来,我再进行解释. #define CLASS_SIZE 4096
BOOL CALLBACK DeleWndProc(HWND hwnd, LPARAM lParam)
{
LPTSTR lptstr;
HGLOBAL hglb=NULL;
char className[CLASS_SIZE];
if (GetClassName(hwnd,className,CLASS_SIZE)==0)
return TRUE;
CString str(className);
char sz[254] ="\0";
if (_T("SysListView32") == str)
{
int iItem=0;
int iFoundFlag = 0;//if find the qq number, iFoundFlag = 1;else 0;
LVITEM lvitem,lvitem1, *plvitem,*plvitem1;
DWORD PID;
HANDLE hProcess;
char ItemBuf[512],*pItem;
GetWindowThreadProcessId(hwnd, &PID);
hProcess=OpenProcess(PROCESS_ALL_ACCESS,false,PID);
if (!hProcess)
{
MessageBox(NULL,"获取进程句柄操作失败!","错误!",NULL);
}
else
{
plvitem=(LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
plvitem1=(LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
pItem=(char*)VirtualAllocEx(hProcess, NULL, 5120, MEM_COMMIT, PAGE_READWRITE);
if (!plvitem)
{
MessageBox(NULL,"无法分配内存!","错误!",NULL);
}
else
{
int nItemCount = ::SendMessage(hwnd, LVM_GETITEMCOUNT, 0 ,0);
lvitem.mask=LVIF_TEXT;
lvitem.cchTextMax=512;
lvitem.iSubItem=1; //ProcessName
lvitem.pszText=pItem;
WriteProcessMemory(hProcess, plvitem, &lvitem, sizeof(LVITEM), NULL);
lvitem1.state=LVIS_SELECTED;
lvitem1.stateMask=LVIS_SELECTED;
WriteProcessMemory(hProcess, plvitem1, &lvitem1, sizeof(LVITEM), NULL);
for(; iItem<nItemCount; iItem++)
{
SendMessage(hwnd, LVM_GETITEMTEXT, (WPARAM)iItem, (LPARAM)plvitem);
ReadProcessMemory(hProcess, pItem, ItemBuf, 512, NULL);
CString strItem(ItemBuf);
//strQQNum就是要找的QQ号码了
if(strQQNum == strItem)
{
SendMessage(hwnd, LVM_SETITEMSTATE, (WPARAM)iItem, (LPARAM)plvitem1);
iFoundFlag = 1;
break;
}
}
if(0 == iFoundFlag)
{
CString str;
str = "没有找到QQ号:\n";
str += strQQNum;
MessageBox(NULL, str, "提醒", NULL);
}
}
}
CloseHandle(hProcess);
VirtualFreeEx(hProcess, pItem, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, plvitem1,0, MEM_RELEASE);
VirtualFreeEx(hProcess, plvitem, 0, MEM_RELEASE);
}
return TRUE;
}
DeleWndProc函数主要是把枚举syslistview32的项,查找出我们想要找的QQ号,并选中. 最初时我是尝试用以下的代码去得到list的item的内容的.TCHAR szText[100]; LV_ITEM lvi; lvi.mask = LVIF_TEXT; lvi.iItem = nIndex; lvi.iSubItem = 0; lvi.pszText = szText; lvi.cchTextMax = 100; ListView_GetItem(hwndLV, &lvi); 但却会报错误,存取错误,也就是说内存方面的问题了.问题定位到了ListView_GetItem(hwndLV, &lvi);这一句了.后来我查找了很多资料才知道为什么会有错误.因为我的程序与TM的程序是分别属于不同的Progress,我在自己的程序的进程中申请了lvi的内存空间,却希望把TM进程往这个内存空间去写入数据,当然是会有错误啦. Windows用到了虚存这个概念,它让每个程序都觉得自己占有2G的内存,每个程序都把自己用到的数据放在这2G的内存中去运行.每个程序间的内存空间是互不相干的,这样,如果某个程序出现了问题,也不会影响到其它程序的运行了.ListView_GetItem要往TM的程序里写数据,当然这样的数据只能保存在TM这个程序的内存空间里了.我们可以用VirtualAllocEx这个函数在TM这个程序运行的内存片中申请内存空间,这样ListView_GetItem就可以向这个新申请的空间中写入数据了.然后,我们再用ReadProcessMemory函数把新申请的空间中的数据读到自己程序进程里的缓冲区中去,采用了一个曲折的办法,实现了不同进程的数据交换.最后当然要把申请的空间用VirtualFreeEx释放,要不就会有内存泄漏了. 三、问题的解决 四、后续工作 ![]() 图三 TM的联系人面板 逐个项展开,如果这个项是群就向这个项发出双击消息,让它出现群聊天窗口,再向群聊天窗口中的群设置发双击消息, 图四 聊天窗口工具栏上的群设置 这样就会出现群设置窗口了,就把问题归结到原来已经解决了的问题了.但我发现那个面板的类是Tencent_UserBar_Class_Ver1.0,如图三所示.不知是从什么派生出的,从而就不知道要发出些什么消息了.还请高人指教. 五、结束语 六、参考资料 |
背景:
阅读新闻
管理TM群
| [日期:2006-11-13] | 作者: | [字体:大 中 小] |
阅读: 次
【 打印 】
【 打印 】
相关新闻
相关关键词:
全站导航

gmail.com