随笔-16  评论-116  文章-0  trackbacks-0
转载请注明出处:http://www.cppblog.com/greatws/archive/2009/05/05/81996.html

这段时间GF一直在玩QQ找茬,看了一下,原理很简单,就是找到2附图片的不同之处,那么程序的思路也就很明了了,就是抓图,存入buffer,比较,显示,这么一个过程。闲话不多说了,下面我用MFC来实现它。

首先先要拿到QQ找茬从窗口的句柄,拿到句柄想咋搞就咋搞,哈哈。当然也可以不要句柄,直接屏幕截图,不过那样就要保证窗口在某个特定的位置,不如句柄来的方便。嗯,还是拿句柄吧,就FindWindow这个函数吧,至于窗口名和类名,用spy++就好啦。

得到句柄之后,接下来要做的是获得窗口大小及设备DC,然后利用CreateCompatibleBitmap函数,创建与QQ找茬窗口DC兼容的BITMAP对象,针对左右2副图,创建2个,便于以后的比较,然后根据坐标偏移,这个用photoshop可以数出来,利用BitBlt函数复制QQ找茬窗口DC里的位图数据进入创建好的BITMAP对象,然后再把BITMAP中的位图数据复制到内存Buffer中,CopyBMPToBuffer是我对GetDIBits函数做了一下简单的封装,少了几个参数而已。代码如下:

BOOL CFindDlg::CopyWindowBlt(CWnd *pWndSrc)
{
    
if(pWndSrc == NULL)    
    
{
        
return FALSE;
    }


    CRect cRect, cRectClient;
    pWndSrc
->GetWindowRect(&cRect);
    pWndSrc
->GetClientRect(&cRectClient);
    pWndSrc
->ClientToScreen(&cRectClient);

    CDC 
*pSrcDC = NULL;  
    CDC cNewDC;
    CBitmap cBitmapLeft, cBitmapRight;
    BITMAPINFO bi;

    pSrcDC 
= pWndSrc->GetDC();
    
//create Compatible Bitmap with the game window
    cBitmapLeft.CreateCompatibleBitmap(pSrcDC, m_nPicWidth, m_nPicHeight);
    cBitmapRight.CreateCompatibleBitmap(pSrcDC, m_nPicWidth, m_nPicHeight);
    cNewDC.CreateCompatibleDC(pSrcDC);
    CBitmap
* pcOldBitmap = cNewDC.SelectObject(&cBitmapLeft);
    
//copy bitmap to dc
    cNewDC.BitBlt(00, m_nPicWidth, m_nPicHeight, pSrcDC, 
        m_nLeftPicLeftTopX 
- (cRectClient.left - cRect.left), 
        m_nLeftPicLeftTopY 
- (cRectClient.top - cRect.top), SRCCOPY);

    CopyBMPToBuffer(cNewDC.GetSafeHdc(), (HBITMAP)cBitmapLeft.GetSafeHandle(), m_pBufLeft, 
&bi);

    cNewDC.SelectObject(
&cBitmapRight);
    cBitmapLeft.DeleteObject();

    cNewDC.BitBlt(
00, m_nPicWidth, m_nPicHeight, pSrcDC, 
        m_nRightPicLeftTopX 
- (cRectClient.left - cRect.left), 
        m_nRightPicLeftTopY 
- (cRectClient.top - cRect.top), SRCCOPY);

    CopyBMPToBuffer(cNewDC.GetSafeHdc(), (HBITMAP)cBitmapRight.GetSafeHandle(), m_pBufRight, 
&bi);

    cNewDC.SelectObject(pcOldBitmap);
    cBitmapRight.DeleteObject();
    cNewDC.DeleteDC();
    pWndSrc
->ReleaseDC(pSrcDC);

    
return TRUE;
}

 

完成上述工作以后,要比较的位图已经在2块buffer中了,数学建模完成了,已经转化成数学问题了,下面要做的就是比较数组中的数据和显示了。这里我没有用2维数组来做比较,简单的用一下一维就好啦。建立一块新的buffer,全部置为蓝色,这样可以设置alpha透过,以便直接在QQ找茬窗口上面直接显示差异,稍后就会看到效果。比较算法如下,很简单,找到不同处涂为黄色,临近的左右2点图为红色,iDifFlag是为了只涂边缘的点,实际用下来效果不是很好,如果有更好的算法,请告诉我,其中MAKECOLOR是类似COLORREF的一个宏#define MAKECOLOR(r, g, b) (0xff000000 | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff))


        for (int i = iLen - 1; i >= 0; i--)
        
{
            pdwDstBuf[i] 
= MAKECOLOR(00255);  //all colors fill blue, in order to set alpha blend
            if ((pdwLeft[i] != pdwRight[i] && iDifFlag == 0||
                (pdwLeft[i] 
== pdwRight[i] && iDifFlag == 1))
            
{

                pdwDstBuf[i] 
= MAKECOLOR(2552550);
                
if (iDifFlag == 0)
                
{
                    
//first different in one time
                    iDifFlag = 1;
                }

                
else
                
{    
                    iDifFlag 
= 0;
                }


                
//nearby points
                if (i + 1 < iLen)
                
{
                    pdwDstBuf[i 
+ 1= MAKECOLOR(25500);
                }

                
if (i - 1 >= 0)
                
{
                    pdwDstBuf[i 
- 1= MAKECOLOR(25500);
                }

                
if (i + 2 < iLen)
                
{
                    pdwDstBuf[i 
+ 2= MAKECOLOR(25500);
                }

                
if (i - 2 >= 0)
                
{
                    pdwDstBuf[i 
- 2= MAKECOLOR(25500);
                }

                i 
-= 2;
            }

        }


然后呢?最后一步了,就是将比较好的位图显示出来,我这里用到CreateBitmap和CreatePatternBrush这2个函数,然后再利用FillRect刷到窗口中,再把窗口用SetLayeredWindowAttributes设置为蓝色透过,然后移动到QQ找茬窗口上方,这样就OK了。不过CreateBitmap要把图片行序颠倒一下,我懒得转2维数组,直接用偏移搞了一下,OK哈哈。

     for (DWORD i = 0; i < PIC_HEIGHT / 2; i++)
     
{
        
for (DWORD j = 0; j < PIC_WIDTH; j++)
        
{
             temp 
= *((DWORD*)pBuf + i * PIC_WIDTH + j);
             
*((DWORD*)pBuf + i * PIC_WIDTH + j) = *((DWORD*)pBuf + PIC_WIDTH * (PIC_HEIGHT - 1 - i) + j);
             
*((DWORD*)pBuf + PIC_WIDTH * (PIC_HEIGHT - 1 - i) + j) = temp;
        }

     }



    cBM.CreateBitmap(PIC_WIDTH, PIC_HEIGHT, 
132, pBuf);
    m_cBr.CreatePatternBrush(
&cBM);
    cBM.DeleteObject();


最后用SetWindowPos将显示差异的窗口置为顶层窗口。效果图如下:


目前已知的问题:区域标示很奇怪,是算法的问题,上面我也说过了,有个flag,因为不能保证2附图片的点与点完全不同,所以这样的效果也是显而易见的。
下载: 可执行程序 (适用于2种找茬游戏,其实就是窗口大小不同)

By greatws
posted on 2009-05-06 00:13 greatws 阅读(4218) 评论(15)  编辑 收藏 引用

评论:
# re: QQ找茬辅助工具的制作 2009-05-06 07:45 | fly931
你太有才了!!  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-06 09:48 | foxtail
讨厌做外挂的 游戏的可玩性都被破坏了  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-06 12:38 | 游客9527
没有考虑效率??呵呵,这年头CPU多就是好做事。  回复  更多评论
  
# re: QQ找茬辅助工具的制作[未登录] 2009-05-06 13:02 |
牛哄哄!  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-06 13:15 | greatws
@游客9527
就是数组比较阿,有啥效率问题?我A3000+的机器,很老了,也没发现速度慢。等I7+DDR3便宜点再换  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-06 15:47 | Pencil.C++
@foxtail

谁又没有逼你用。
  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-06 16:34 | 一抹微蓝
@foxtail
你编出来也算你牛
爱用不用...  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-06 19:38 | 陈梓瀚(vczh)
不怪,是JPG的压缩问题。结果很正常。  回复  更多评论
  
# re: QQ找茬辅助工具的制作[未登录] 2009-05-06 22:16 | fangfang
牛人~
果然牛人~~  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-05-07 17:10 | coder
源码贡献出来呗,新手有点不懂  回复  更多评论
  
# re: QQ找茬辅助工具的制作[未登录] 2009-05-08 09:26 | megax
单纯的像素比较啊。。。。有一个像素不一样就完蛋了。。。所以反这个也很好弄。  回复  更多评论
  
# re: QQ找茬辅助工具的制作[未登录] 2009-05-08 09:28 | megax
比如同一个图片采用不同的研所算法。。。。  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2009-08-20 17:19 | 刘雅思
您的工具很好,要是有窗口置顶功能、标示不同区域的快捷键和换图片时自动清除标示的功能就更好了。  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2011-07-01 12:54 | 冬仔
麻烦你能不能给下源码?747099039@qq.com 谢了。。  回复  更多评论
  
# re: QQ找茬辅助工具的制作 2011-07-01 15:32 | 冬仔
就是,还望大牛多多帮助。。@coder
  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理