间谍行动——窗体探测器

来源:互联网 发布:nginx异步写入日志 编辑:程序博客网 时间:2024/05/02 02:21
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 160x600, 创建于 08-4-23MSDN */google_ad_slot = "4367022601";google_ad_width = 160;google_ad_height = 600;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>

间谍行动——窗体探测器

最近心血来潮,对spy深感兴趣,便准备进行一次间谍行动,目标很简单,利用EnableWindow函数激活不可用或无效的控件按钮,当然,这窗体探测器是必不可少了,原以为很简单,但实际行动起来,却遇到不少麻烦,现将经过记录下来,供有兴趣的朋友参考。

我们大都见过spyxx中的窗体探测器,当鼠标在窗体探测器上按下左键时,更改鼠标样式,同时捕获鼠标,探测鼠标下的窗体直到鼠标左键松开。这样我们可以写出代码框架了:

  case WM_LBUTTONDOWN://鼠标左键按下,检测拖动还是探测    {      MSG msg;      //在窗体探测器中按下鼠标      if(在窗体探测器内==TRUE)//替换光标,探测拖动      {        //更改鼠标样式        SetCursor(...);        //捕获鼠标        SetCapture(hWnd);        hWndNow=NULL;//当前窗体设为空//此为全局变量        //获取鼠标移动消息        while(GetMessage(&msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST))        {          if((msg.message==WM_MOUSEMOVE)||(msg.message==WM_NCMOUSEMOVE))          {              HWND hWndPoint;              //设置光标              SetCursor(LoadCursor(hInst, (LPCTSTR)CUR_WINDOWSPY));              GetCursorPos(&Point);              //探测当前鼠标点              if(hWndPoint=WindowFromPoint(Point))              {                if(hWndNow!=hWndPoint)//目标已改变                {                  if(hWndNow)                  {                    //清除旧目标上的黑框                    XorBorder(hWndNow);                  }                  //并且不属于本线程                  if(GetWindowThreadProcessId(hWndPoint,NULL)!=GetCurrentThreadId())                  {                    //将当前窗体画一黑边框                    hWndNow=hWndPoint;                    XorBorder(hWndNow);                  }                  else                  {                    hWndNow=NULL;                  }  //显示窗体信息                  ShowWindowMessage(hWnd,hWndNow);                }              }              else              {                hWndNow=NULL;                ShowWindowMessage(hWnd,hWndNow);              }          } //如果左键松开,则跳出          else if(msg.message==WM_LBUTTONUP)          {            break;          }        }        XorBorder(hWndNow);        //释放鼠标并恢复鼠标样式        SetCursor(LoadCursor(NULL,(LPCTSTR)IDC_ARROW));        ReleaseCapture();      }      break;    }
这里的问题就在 WindowFromPoint 和 XorBorder 中.这里我们先看第一版XorBorder:
void XorBorder(HWND hWnd){  RECT rect;   //当前窗体区域  HDC hdc=GetWindowDC(hWnd);  GetWindowRect(hWnd,&rect);  //调整边框  rect.bottom-=rect.top;  rect.right-=rect.left;  rect.left=rect.top=0;  SetROP2(hdc,R2_NOT);  FrameRect(hdc,&rect,GetStockObject(BLACK_BRUSH));  ReleaseDC(hWnd,hdc);}
然而结果总以失败告终,查看SetROP2资料,隐隐约约感觉它仅对画笔起作用,画刷无效(仅代表个人观点,正误难辨)。于是将其改为Rectangle,然而它可是连边框带矩形内部全部搞定了,这并不是我要的效果呀,这该怎么办呢?看我的最终解决方案:
void XorBorder(HWND hWnd){  HPEN hPen,hOldPen;  RECT rect;   //当前窗体区域  HDC hdc=GetWindowDC(hWnd);  GetWindowRect(hWnd,&rect);  //调整边框  rect.bottom-=rect.top;  rect.right-=rect.left;  rect.left=rect.top=0;  SetROP2(hdc,R2_NOT);  hPen=CreatePen(PS_SOLID,6,RGB(0,0,0));  hOldPen=SelectObject(hdc,hPen);  //选择刷子为空,使矩形不填充内部  SelectObject(hdc,GetStockObject(NULL_BRUSH));  Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);  SelectObject(hdc,hOldPen);  DeleteObject(hPen);   ReleaseDC(hWnd,hdc);}
我将当前画刷选择为空,我不知道这种方法是否正统,反正msdn未找到,虽然看着仅仅是小小的改动,倒是费了我好大功夫,我可是一直在FrameRect上打转呀!

现在我们开看 WindowFromPoint :msdn上说该函数跳过无效按钮,需要使用ChildWindowFromPoint来解决,然而,问题并不是那么简单,先看下面这段资源文件:

IDD_DIALOG1 DIALOGEX 0, 0, 186, 110STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |     WS_SYSMENUCAPTION "Dialog"FONT 8, "MS Shell Dlg", 400, 0, 0x1BEGIN    GROUPBOX        "静态",IDC_STATIC,45,14,81,69    CONTROL         "选中1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,                    57,28,61,16    CONTROL         "选中1",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,                    57,54,60,10END
我试验过,要想得到IDC_CHECK1,IDC_CHECK2,用上面的两个函数是无法实现的,(你知道吗,GROUPBOX是button类,而不是static,直到今天我才知道),请不要告诉我改变GROUPBOX的Tab键顺序,我们的探测器要面对各种情况,下面看我的解决方案:
HWND BrotherWindowFromPoint(HWND hWndPoint,const POINT Point){  //检测兄弟窗口    RECT rcPoint;    RECT rcNow;    HWND hWndBrother=hWndPoint;//GetWindow(hWndPoint,GW_HWNDFIRST);    hWndPoint=NULL;    do    {      if(GetWindowStyle(hWndBrother)&WS_VISIBLE)//可见      {        GetWindowRect(hWndBrother,&rcNow);        if(PtInRect(&rcNow,Point))        {          //检验矩形嵌套情况          if(hWndPoint==NULL)          {            hWndPoint=hWndBrother;            rcPoint=rcNow;          }          else if(            ((rcNow.bottom<rcPoint.bottom)&&(rcNow.bottom>rcPoint.top)&&(rcNow.left>rcPoint.left)&&(rcNow.left<rcPoint.right))//左下角            ||((rcNow.bottom<rcPoint.bottom)&&(rcNow.bottom>rcPoint.top)&&(rcNow.right>rcPoint.left)&&(rcNow.right<rcPoint.right))//右下角            ||((rcNow.top>rcPoint.top)&&(rcNow.top<rcPoint.bottom)&&(rcNow.left>rcPoint.left)&&(rcNow.left<rcPoint.right))//左上角            ||((rcNow.top>rcPoint.top)&&(rcNow.top<rcPoint.bottom)&&(rcNow.right>rcPoint.left)&&(rcNow.right<rcPoint.right))//右上角            )          {            hWndPoint=hWndBrother;            rcPoint=rcNow;          }        }      }    }while(hWndBrother=GetWindow(hWndBrother,GW_HWNDNEXT));    return hWndPoint;}
该函数检测同层窗口,获得指定点内,嵌套最深的窗口,由此我们便可以生成我们自己的WindowFromPoint
HWND MyWindowFromPoint(const POINT Point){  HWND hWndPoint=WindowFromPoint(Point);  if(hWndPoint)  {    //宽度搜索兄弟窗口    HWND hWndChild;    if(!(GetWindowLong(hWndPoint,GWL_STYLE)&WS_CHILD))//顶层窗口      return hWndPoint;    //非顶层窗口,要进行兄弟查找.    hWndPoint=MyBrotherWindowFromPoint(hWndPoint,Point);    assert(hWndPoint);    //深度搜索子窗口    while(hWndChild=GetTopWindow(hWndPoint))    {      //宽度搜索兄弟子窗口      if(NULL==(hWndChild=MyBrotherWindowFromPoint(hWndChild,Point)))        break;      hWndPoint=hWndChild;    } //*/  }  return hWndPoint;}

该函数首先判断是否是顶层窗体,如果不是,首先进行宽度搜索,虽然麻烦了些,然而却不得不如此。顺便说一下,vc资源编辑器中正在设计的对话框拥有disable属性,spyxx你的窗体探测器也不能得到其内的所有控件句柄,而该函数所向无敌,如果去掉BrotherWindowFromPoint函数内的可见性判断,隐藏窗体也无处藏身。有兴趣的朋友可以亲自设计一下,如果你是懒惰者,可到华军软件园下在该程序红色间谍.

个人主页:http://ggg82.126.com

电子邮件:<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>

<script type="text/javascript"><!--google_ad_client = "pub-2947489232296736";/* 160x600, 创建于 08-4-23MSDN */google_ad_slot = "4367022601";google_ad_width = 160;google_ad_height = 600;//--></script><script type="text/javascript"src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
原创粉丝点击