管理TM群
2007-03-15 21:54:42 来源:WEB开发网二、问题的分析
我在实现时使用的是TM2006新春版,在群聊天的窗口里点工具务栏上的"群设置",弹出了"群设置"窗口,在这个窗口里,选择"成员列表"这一项,右边有一个list,这个list就包含有所有的成员了,当选中了某个人后,就可把它T了.
图一 群设置窗口
现在的问题是要先把想T的人找出来.怎么样在list中把想T的人给找出来呢,我的想法是枚举这个list里所有人的QQ号,然后跟想要T的QQ号作比较,如果有相同的,就把list里的这一项选中,然后我们就可以进一步的操作了.那现在就可以把问题转化为,枚举list,获得list里的项的信息.我用spy++查看了一下那个"群设置"窗口,如图所示:
图二 用spy++查看的窗口关系
最顶层的就是那个"群设置"窗口了,那个显示成员的list原来是一个syslistview32类型的控件,包含在一个类型为"#32770"的dialog中,我们只要顺着最顶层的窗口中,一层层的窗口找下去就可以得到我个想要的那个list窗口的名柄了,呵呵,之后,就可以向这个list发出消息,让它干活了.想到这,偶心时狂喜了一阵子.但是在实现过程中却是不是那么的顺利的.在顶层窗口中找那个list的句柄,并不是什么困难的事.把桌面上的把有窗口都枚举一遍,就要以找到窗口名为”群设置”的窗口了.
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] ="";
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号:
";
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释放,要不就会有内存泄漏了.
三、问题的解决
- ››管理/var/spool/clientmqueue/下的大文件
- ››管理私有云,第 2 部分: 使用 WebSphere CloudBur...
- ››管理 Eclipse 环境:Eclipse 维护的神秘艺术
- ››管理私有云:WebSphere CloudBurst Appliance 命令...
- ››管理启动项 - Windows 7中的BCDEDIT命令
- ››管理Exchange 2003注意事项
- ››TM终更新 搜狗浏览器发力
- ››管理好超级管理员帐户堵住系统漏洞
- ››管理数据中心资源池需要注意的事项
- ››管理虚拟化环境的两大重要标准:VMAN和OVF
- ››管理与技术有机结合 保障网络安全运行
- ››管理Windows内部数据库(MICROSOFT##SSEE)实例
更多精彩
赞助商链接