龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > VC开发 >

用Visual C++设计QQ群管理工具[组图](3)

时间:2009-12-30 15:42来源:未知 作者:admin 点击:
分享到:
//枚举包含有syslistview32的类型为#32770的窗口的句柄 BOOL CALLBACK ChildWndProc(HWND hwnd, LPARAM lParam) { LPTSTR lptstr; HGLOBAL hglb=NULL; char className[CLASS_SIZE]; if (GetClassName

//枚举包含有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; p 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释放,要不就会有内存泄漏了.


  三、问题的解决

  至此,再回头看看文中开头提到的两个问题. 1查找到有特殊标志的QQ号的名字,只要修改DeleWndProc中的匹配QQ号的语句就行了.这个纯粹是一个字符串的匹配了. 2查找指写的的QQ号. DeleWndProc已经是查找指定的QQ号了.示例程序给出的就是这种情况. 当已经找到指定的项时,就可以向那个删除成员Button发出一个BM_Click的消息了,呵呵,人就给T了.这个也不难实现,也照样的找到这个按钮的 HWND,用SendMessage就可以把消息发送过去了.至此就解决了开头提出的两个问题了. 在查找群设置的窗口时,也可以用FindWindow和FindWindowEx来得到syslistview32的句柄.

  四、后续工作

  我在把程序也给另一个管理员用的时候,他给我提出要实现以下的功能: 输入被T的QQ号,软件自动搜索自己是管理员的群,软件能在自己是管理员的群中搜索到此QQ号,把这个人在每个群里都T走. 呵呵,我的想法模拟人的操作过程,把TM的联系人面板打开,

图三 TM的联系人面板


  逐个项展开,如果这个项是群就向这个项发出双击消息,让它出现群聊天窗口,再向群聊天窗口中的群设置发双击消息,

图四 聊天窗口工具栏上的群设置

  这样就会出现群设置窗口了,就把问题归结到原来已经解决了的问题了.但我发现那个面板的类是Tencent_UserBar_Class_Ver1.0,如图三所示.不知是从什么派生出的,从而就不知道要发出些什么消息了.还请高人指教.

  五、结束语

  从vckbase学到了很多东西,很感谢大家的共同分享.自己的水平还很菜,但还是把自己碰到的问题写出来了,一方面可以给像我同样的菜鸟吸取经验教训,再碰到同样的问题时,能有一些参考资料.另一方面,是让各位高人指点一下我的不足. 欢迎用下面的联系方式与我继续讨论。

精彩图集

赞助商链接