【世界快播报】如何用计算机制作美女找茬?QQ美女找茬辅助器制作

发布时间:   来源:CSDN  

最近,有朋友总要跟我PK QQ美女找茬,无奈在下眼力实在是不如人。不过,咱可是计算机专业的啊,自己找不过他,还不能利用计算机来找吗?嘿嘿,于是开始研究这个辅助工具。


(资料图片)

首先,先看看截图:

下面说说制作的方法。我想,大家应该也能想通制作的方法:获取窗口句柄->找到图片(两张)->对比->设置成不同的颜色->显示出来。

过程是很简单的,先看看第一步,获取窗口句柄

Code: // 获取游戏句柄   bool CMain::GetGameHandle(void)   {       m_pGame = FindWindow(NULL, _T("大家来找茬"));       if(m_pGame == NULL)           return false;       else          return true;   }

这里用到了一个FindWindow()函数,函数原型如下

HWND FindWindow(LPCSTR lpClassName,LPCSTR lpWindowName);

利用窗口名称获取到一个窗口HWND.

然后,很重要的就是获取图片了,把图片要先存入一个缓冲区,以下是代码:

Code: // 将游戏中位图数据复制到内存中   bool CMain::CopyPicToBlt(DWORD*& lpvBits,  int xSrc, int ySrc, int nWidth, int nHeight)   {           HWND hWnd = m_pGame;//主游戏句柄             HDC hSrcDC=NULL;           HDC hNewDC;           //图片格式信息头           BITMAPINFOHEADER   bi;           bi.biSize = sizeof(BITMAPINFOHEADER);               bi.biWidth = nWidth;               bi.biHeight = nHeight;             bi.biPlanes = 1;               bi.biBitCount = 32;               bi.biCompression = BI_RGB;               bi.biSizeImage = nWidth*nHeight;             bi.biXPelsPerMeter = 0;               bi.biYPelsPerMeter = 0;               bi.biClrUsed = 0;               bi.biClrImportant = 0;             HBITMAP pBitmap;           hSrcDC=GetDC(hWnd);//获取程序DC           hNewDC = CreateCompatibleDC(hSrcDC);//创建兼容DC           pBitmap = CreateCompatibleBitmap(hSrcDC, nWidth, nHeight);//设置图大小           SelectObject(hNewDC, pBitmap);  //绑定图片             //将位图复制到DC中           BitBlt(hNewDC, 0, 0, nWidth, nHeight, hSrcDC, xSrc, ySrc, SRCCOPY);            //为图片申请一块内存空间           if(lpvBits)           {               delete[] lpvBits;               lpvBits=NULL;           }                      lpvBits = new DWORD[nWidth*nHeight];           if(!lpvBits)           {               return false;           }           //将图片数据存储到对应的变量中           GetDIBits(hNewDC, pBitmap, 0, (UINT)m_nPicHeight, lpvBits, (BITMAPINFO *)&bi, DIB_RGB_COLORS);           DeleteObject(pBitmap);           DeleteDC(hNewDC);           return true;   }

这里,要先简单说下BMP图片的知识。BMP图片其实在计算机里也是以二进制的方式存储的(任何文件其实都是),这样,我们用一个DWORD指针来作为BUFFER,方便比较。通过这个函数,就把窗口中(xSrc, ySrc)位置的(nWidth, nHeight)大小的位图存储到了lpvBits指向的缓冲区了,以后直接比较两个缓冲区的内容即可。

Code: // 比较两个图片     void CMain::CompareBMP(DWORD*& pBuffer, DWORD* pLeft, DWORD* pRight)   {       if(!pBuffer)       {           delete[] pBuffer;           pBuffer=NULL;       }       pBuffer = new DWORD[m_nPicWidth*m_nPicHeight];       //比较两幅图,数据相同的设置为白色,不同的为红色。       for (DWORD i = 0; i < (DWORD)m_nPicWidth * m_nPicHeight; i++)       {           if(pLeft[i] != pRight[i])                pBuffer[i] = RGB(0,0,255);            else              pBuffer[i] = RGB(255,255,255);        }       //SaveBMP(pBuffer, _T("d://result1.bmp") );       //转换图片数据,使图片按正常顺序显示。(BMP格式与窗口图像存放竖坐标相反)       int width = m_nPicWidth;       for (DWORD i = 0; i < (DWORD)(m_nPicHeight / 2); i++)       {           for (DWORD j = 0; j < (DWORD)width; j++)           {               DWORD temp;               temp = *(pBuffer + i * width + j);               *(pBuffer + i * width + j) = *(pBuffer + width * (m_nPicHeight - 1 - i) + j);               *(pBuffer + width * (m_nPicHeight - 1 - i) + j) = temp;           }       }       //SaveBMP(pBuffer, _T("d://result2.bmp") );       if(pLeft)       {           delete[] pLeft;           pLeft = NULL;       }       if(pRight)       {           delete[] pRight;           pRight = NULL;       }   }

最后通过上面的来比较图片。当然,这个算法是最简单的算法,就是利用循环,按顺序比较,再将结果填充到一个新的缓冲区里,把原先的两张图片缓冲区内内容清除掉

然后,就是显示出来了,首先要先创建一个半透明的对话框

Code: // 点击查找后   void CFindFaultDlg::FindFault(void)   {       if(!m_GameMain.GetGameHandle())       {           MessageBox( _T("请先打开"QQ美女找茬"游戏"), _T("温情提示"));           return;       }       DWORD* pBuffer=NULL;              //创建一个对话框,用于显示找茬游戏中两幅图的不同点       if(m_pDlg)           m_pDlg->DestroyWindow();       m_GameMain.FindingFault(pBuffer);       m_pDlg = new CDialog();       if(m_pDlg)       {           if(!m_pDlg->Create(IDD_DLGSHOW, this))            {               MessageBox( _T("对话框初始化失败"), _T("温情提示") );               return ;           }                      //利用SetLayeredWindowAttributes设置窗口透明。           //自带的SDK不支持,需要更新才能直接使用这个函数。           //SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^WS_EX_LAYERED);            //SetLayeredWindowAttributes(this->m_hWnd,0,128,2);            //           //动态的从User32.dll中取得SetLayeredWindowAttributes函数地址。WS_EX_LAYERED = 0x80000           SetWindowLong(m_pDlg->GetSafeHwnd(),GWL_EXSTYLE, GetWindowLong(m_pDlg->GetSafeHwnd(),GWL_EXSTYLE)^0x80000| WS_EX_TRANSPARENT);            HINSTANCE hInst=LoadLibrary(_T("User32.DLL"));            if(hInst)            {                typedef BOOL  (WINAPI * MYFUNC)(HWND,COLORREF,BYTE,DWORD);                MYFUNC fun=NULL;                               //取得SetLayeredWindowAttributes函数指针                fun=(MYFUNC)GetProcAddress(hInst,"SetLayeredWindowAttributes");                if(fun)                    fun(m_pDlg->GetSafeHwnd(),0,128,2);                FreeLibrary(hInst);            }                       //移动该对话框窗口,置顶,覆盖找茬游戏界面中右边的那幅图。           CRect rect;           CWnd* pGameWnd = FindWindow(NULL, _T("大家来找茬"));           pGameWnd->GetClientRect(&rect);           pGameWnd->ClientToScreen(&rect);           if(!m_pDlg->SetWindowPos(&wndTopMost, rect.left + m_ShowOffsetX, rect.top + m_ShowOffsetY,               497, 448, SWP_SHOWWINDOW))            {               MessageBox(_T("设置对话框失败!"), _T("温情提示"));               return;           }       }          else      {           MessageBox(_T("创建对话框对象失败!"), _T("温情提示"));           return;       }       //显示不同       CDC* pShow = m_pDlg->GetDC();       ShowFault(pShow,pBuffer);       //m_GameMain.SaveBMP(pBuffer, _T("D://result3.bmp") );       if(pBuffer)       {           delete[] pBuffer;           pBuffer = NULL;       }      }

上面的函数不仅显示了对话框,而且将位置通过SetWindowPos()调整到当前游戏窗口中图片的上方

然后就是把不同的地方显示出来

Code: // 显示不同的地方   void CFindFaultDlg::ShowFault(CDC* pDC, DWORD* pBuffer)   {       CBitmap bm;       bm.CreateBitmap(m_GameMain.GetPicFrame().x,m_GameMain.GetPicFrame().y,1,32, pBuffer);       //bm.LoadBitmap(_T("I://result.bmp"));       CBrush brush;       brush.CreatePatternBrush(&bm);              CBrush* pOldBrush = (CBrush*)pDC->SelectObject(&brush);              pDC->FillRect(&CRect(0, 0, m_GameMain.GetPicFrame().x,m_GameMain.GetPicFrame().y),&brush);              pDC->SelectObject(pOldBrush);              brush.DeleteObject();       bm.DeleteObject();       ReleaseDC(pDC);   }

这里是用刚才比较结束后的缓冲区内容的位图信息创建了一个画刷brush,然后用该画刷填充整个窗口,这样就结束了。

后记:通过制作这个小小的辅助工具,了解了获取句柄的方法,遇到了许多问题,比如32位位图和24位位图就有很大区别。

还有半透明窗口的显示。而且,最后遇到了一个很诡异的问题,这个程序到这里在我自己的电脑上都很正确,可是当我在我家的电脑上使用的时候,就总是在中间多出来一个方块的东西,而且只能显示一次,再点显示也是无效,无奈在家电脑也装上VS来调试,调试的时候也没发现什么问题,该执行的语句都执行了。如果有哪位高手知道这个问题的答案,还望多多指教。顺便说一句,我的系统是Win7,家中的是Vista。

为了解决这个问题,我最后采用了另外一种方法:不是通过截取窗口,而是截取屏幕,结果就正常了。。。

Code: // 通过截屏来获取图像   bool CMain::GetPicByCap(DWORD*& lpvbits, int xSrc, int ySrc, int nWidth, int nHeight)   {       HWND hWnd = m_pGame;    //得到句柄       HDC hdcScreen;       HDC hdcWindow;       HDC hdcMemDC = NULL;       HBITMAP hbmScreen = NULL;       BITMAP bmpScreen;         // Retrieve the handle to a display device context for the client        // area of the window.        hdcScreen = GetDC(NULL);       hdcWindow = GetDC(hWnd);       hdcMemDC = CreateCompatibleDC(hdcWindow);          if(!hdcMemDC)       {           MessageBox(hWnd, L"StretchBlt has failed",L"Failed", MB_OK);           goto done;       }         // Get the client area for size calculation       RECT rcClient;       GetClientRect(hWnd, &rcClient);       POINT pPos;       pPos.x = xSrc;       pPos.y = ySrc;       ClientToScreen(hWnd, &pPos);//转换坐标       //This is the best stretch mode       //SetStretchBltMode(hdcWindow,HALFTONE);                  // Create a compatible bitmap from the Window DC       hbmScreen = CreateCompatibleBitmap(hdcScreen, nWidth, nHeight);              if(!hbmScreen)       {           MessageBox(hWnd, L"CreateCompatibleBitmap Failed",L"Failed", MB_OK);           goto done;       }         // Select the compatible bitmap into the compatible memory DC.       SelectObject(hdcMemDC,hbmScreen);              // Bit block transfer into our compatible memory DC.       if(!BitBlt(hdcMemDC,                   0,0,                   nWidth, nHeight,                  hdcScreen,                   pPos.x, pPos.y,                  SRCCOPY))       {           MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);           goto done;       }         // Get the BITMAP from the HBITMAP       GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);               BITMAPFILEHEADER   bmfHeader;           BITMAPINFOHEADER   bi;               bi.biSize = sizeof(BITMAPINFOHEADER);           bi.biWidth = bmpScreen.bmWidth;           bi.biHeight = bmpScreen.bmHeight;         bi.biPlanes = 1;           bi.biBitCount = 32;           bi.biCompression = BI_RGB;           bi.biSizeImage = 0;         bi.biXPelsPerMeter = 0;           bi.biYPelsPerMeter = 0;           bi.biClrUsed = 0;           bi.biClrImportant = 0;         DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;       if(lpvbits)       {           delete[] lpvbits;           lpvbits = NULL;       }       lpvbits = new DWORD[nWidth*nHeight];         // Gets the "bits" from the bitmap and copies them into a buffer        // which is pointed to by lpbitmap.       GetDIBits(hdcWindow, hbmScreen, 0,           (UINT)bmpScreen.bmHeight,           lpvbits,           (BITMAPINFO *)&bi, DIB_RGB_COLORS);           //Clean up   done:       DeleteObject(hbmScreen);       ReleaseDC(hWnd, hdcMemDC);       ReleaseDC(NULL,hdcScreen);       ReleaseDC(hWnd,hdcWindow);           return true;   }

这个是从MSDN上参考而来的。其实很简单,就是用ClientToScreen(hWnd, &pPos);把窗口中的坐标转换为对应的屏幕坐标,其他的和第一个是一样的。

附:

各图片位置,窗口大小等信息,这个找起来很麻烦。。。

m_nPicWidth = 498-1;  //左右两副图本身有偏移1个像素,去掉偏移的,只比较共有的部分  m_nPicHeight = 448;  m_nOffsetLeftPicX = 8;  m_nOffsetLeftPicY = 193;  m_nOffsetRightPicX = 516 + 1;   //左右两副图本身有偏移1个像素,去掉偏移的,只比较共有的部分  m_nOffsetRightPicY = 193;

相关文章Related

返回栏目>>