Spy ++ Principle

Source: Internet
Author: User

Open the VC integrated development environment and create a dialog box-based project. We named this project SpyXX. Draw a Picture Box Control, a Static text Control, two Check Box controls, and a Tab Control in the form ). The interface design is as follows.

  

Two Icon files (. ico) and a mouse cursor file (. cur) for normal display, mouse pull, and mouse pointer; where are these resources? In Spy ++, use exclusive. (I have dug it out from other software. The name is like a super bully. I can't remember it clearly .) The tab control defines five tabs: "regular", "style", "class", "window", and "message ". The content of each tab is created using a Property Page dialog box. Next, we will describe the development process in sequence.

I. Preparation of detectors

The detector is displayed with an image frame control. A targeted icon is displayed normally. When you press the mouse on the top, the displayed content immediately changes to another non-target icon, and the mouse pointer changes to a target. In this way, the target is dragged out. Through the above description, we learned that the image box needs to respond to the WM_LBUTTONDOWN message and WM_LBUTTONUP message. In normal conditions, the image box only responds to the mouse and clicks the message BN_CLICK. Therefore, we need to subscribe to the above two messages.

Set the ID of the image box to IDC_PIC and select the Notify attribute (otherwise, the message is not responded ). Choose Insert> New Class from the menu, select MFC Class for Class type, set the Class name to CMyPic, and set the base Class to CStatic. Add the private member variable CMyPic m_pic of the CSpyXXDlg class and associate it with the image box during the initialization of the dialog box. The Code is as follows:

BOOL CSpyXXDlg::OnInitDialog()
{
  CDialog::OnInitDialog();
  m_pic.SubclassDlgItem(IDC_PIC,this);
  ……
  return TRUE;
}
In the cmypic class, we can respond to the messages that are pressed and popped up with the left mouse button. Press Ctrl + W to open the Class Wizard, select the message maps tab, and select cmypic from the class name drop-down list. Add wm_lbuttondown and wm_lbuttonup messages from the messages list, and accept the default function names onlbuttondown and onlbuttonup. The code for icon switching and mouse cursor switching is as follows:Void cmypic: onlbuttondown (uint nflags, cpoint point)
{
// Todo: add your message handler code here and/or call default
Setcapture (); // Mouse capture
Hcursor Hc = loadcursor (afxgetapp ()-> m_hinstance, makeintresource (idc_cursor1 ));
// Idc_cursor1 is the resource Number of the target cursor.
: Setcursor (HC );
Hicon hicon2 = loadicon (afxgetapp ()-> m_hinstance, makeintresource (idi_icon2 ));
// Idi_icon2 indicates the resource Number of the no-target icon.
This-> seticon (hicon2 );
Cstatic: onlbuttondown (nflags, point );
}
Void cmypic: onlbuttonup (uint nflags, cpoint point)
{
// Todo: add your message handler code here and/or call default
Releasecapture (); // release Mouse capture
HICON hicon1 = LoadIcon (AfxGetApp ()-> m_hInstance, MAKEINTRESOURCE (IDI_ICON1 ));
// IDI_ICON1 indicates a resource number with a target icon.
This-> SetIcon (hicon1 );
CStatic: OnLButtonUp (nFlags, point );
}
The appearance of the detector is completed. You can run it first, press the mouse, and drag it to try. The function is as follows: get the window handle. The API functions getcursorpos and windowfrompoint are used to determine the Window Based on the mouse position. In addition, we also want to move the mouse to a place like a graph capture program, and a blinking rectangle will appear around the window. To achieve this, we use a timer. The timer is located in the cspyxxdlg class, but it must be started by onlbuttonup in cmypic. Therefore, we define a global variable g_hme to save the instance handle of cspyxxdlg. At the same time, the selected window handle is also displayed on multiple tabs, so you can save it with the global variable g_hwnd. The other properties page handles used to display tabs are saved by g_hpage0, g_hpage1, g_hpage2, g_hpage3, and g_hpage4 respectively. The code for starting the timer is as follows:FromHandle(g_hMe)->SetTimer(1,600,NULL);In the timer, we need to draw a rectangle within the desktop range. The Code is as follows:POINT pnt;
RECT rc;
HWND export HWND =: getdomaintopwindow (); // obtain the desktop handle
HDC Export DC =: GetWindowDC (export hwnd); // desktop device acquisition scenario
Int oldRop2 = SetROP2 (DeskDC, R2_NOTXORPEN );
: GetCursorPos (& pnt); // obtain the mouse Coordinate
HWND UnHwnd =: WindowFromPoint (pnt); // obtain the window handle at the pointer
G_hWnd = UnHwnd;
: GetWindowRect (g_hWnd, & rc); // obtain the window rectangle.
If (rc. left <0) rc. left = 0;
If (rc. top <0) rc. top = 0;
HPEN newPen =: CreatePen (0, 3, 0); // create a new paint brush and load it into DC
HGDIOBJ oldPen =: SelectObject (rjdc, newPen );
: Rectangle (DeskDC, rc. left, rc. top, rc. right, rc. bottom); // a blinking Rectangle is displayed around the window.
Sleep (400); // sets the blinking interval.
: Rectangle (DeskDC, rc. left, rc. top, rc. right, rc. bottom );
: SetROP2 (DeskDC, oldRop2 );
: SelectObject (structured DC, oldPen );
: DeleteObject (newPen );
: ReleaseDC (mongohwnd, mongodc );
DeskDC = NULL;
At this point, all detector functions are complete.

2. check boxes

The first check box is "always at the top". The Code is as follows:

void CSpyXXDlg::OnChktop()
{
  int nTop=((CButton*)GetDlgItem(IDC_CHKTOP))->GetCheck();
  if(nTop==1)
    :: SetWindowPos(m_hWnd,HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
  else
    ::SetWindowPos(m_hWnd,HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
}
The second check box is "hexadecimal ". Because its value affects the content of the dialog box on multiple property pages, you can use the global variable g_nhex to save it:void CSpyXXDlg::OnChkhex()
{
  g_nHex=((CButton*)GetDlgItem(IDC_CHKHEX))->GetCheck();
}
Here, we also set up a global function display to output the handle values for hexadecimal and 10hexadecimal:CString Display(int nVal)
{
  CString str;
  if(g_nHex==1)
  {
    str.Format("%x",nVal);
    str.MakeUpper();
  }
  else
    str.Format("%d",nVal);
  return str;
}
3. Tab controls

In the tab control, five tabs correspond to five property page dialogs. The classes associated with these tabs are named CPage0, CPage1, CPage2, CPage3, and CPage4. Create private member variables m_page0, m_page1, m_page2, m_page3, and m_page4 in CSpyXXDlg. In the initialization process, create the five property pages dialog box:  m_page0.Create(IDD_OLE_PROPPAGE_LARGE,GetDlgItem(IDC_TAB1));
  m_page1.Create(IDD_OLE_PROPPAGE_LARGE1,GetDlgItem(IDC_TAB1));
  m_page2.Create(IDD_OLE_PROPPAGE_LARGE2,GetDlgItem(IDC_TAB1));
  m_page3.Create(IDD_OLE_PROPPAGE_LARGE3,GetDlgItem(IDC_TAB1));
  m_page4.Create(IDD_OLE_PROPPAGE_LARGE4,GetDlgItem(IDC_TAB1));
  CRect rs;
  m_tab.GetClientRect(rs);
  rs.top+=20;
  rs.bottom-=3;
  rs.left+=3;
  rs.right-=3;
  m_page0.MoveWindow(rs);
  m_page1.MoveWindow(rs);
  m_page2.MoveWindow(rs);
  m_page3.MoveWindow(rs);
  m_page4.MoveWindow(rs);
  m_page0.ShowWindow(SW_SHOW);
  m_tab.SetCurSel(0);
Then, control the display of the message TCN_SELCHANGE in the response function of the tab:void CSpyXXDlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
  // TODO: Add your control notification handler code here
  int i=m_tab.GetCurSel();
  switch(i)
  {
  case 0:
    m_page0.ShowWindow(SW_SHOW);
    m_page1.ShowWindow(SW_HIDE);
    m_page2.ShowWindow(SW_HIDE);
    m_page3.ShowWindow(SW_HIDE);
    m_page4.ShowWindow(SW_HIDE);
    break;
  case 1:
    m_page0.ShowWindow(SW_HIDE);
    m_page1.ShowWindow(SW_SHOW);
    m_page2.ShowWindow(SW_HIDE);
    m_page3.ShowWindow(SW_HIDE);
    m_page4.ShowWindow(SW_HIDE);
    break;
  case 2:
    ……
  default:
    ;
  }
  *pResult = 0;
}
4. Regular Tab

The General tab displays the window handle, window class name, title text, window rectangle, window ID, process ID, and program path. Control of its display or change should be carried out in the WM_LBUTTONUP response function of CMyPic. The Code is as follows:(CPage0 *) FromHandle (g_hPage0)-> m_editHWND.SetWindowText (Display (int) g_hWnd ));
Char strClass [200] = "";
: GetClassName (g_hWnd, strClass, 200 );
(CPage0 *) FromHandle (g_hPage0)-> m_editCLASS.SetWindowText (strClass );
(CPage2 *) FromHandle (g_hPage2)-> SetDlgItemText (IDC_EDITCLASSNAME, strClass); <
    
Char strTitle [200] = "";
: GetWindowText (g_hWnd, strTitle, 200 );
(CPage0 *) FromHandle (g_hPage0)-> m_editTITLE.SetWindowText (strTitle );
Long iWNDID = GetWindowLong (g_hWnd, GWL_ID );
(CPage0 *) FromHandle (g_hPage0)-> m_editWNDID.SetWindowText (Display (int) iWNDID ));
   
Unsigned long iPID = 0;
GetWindowThreadProcessId (g_hWnd, & iPID );
(CPage0 *) FromHandle (g_hPage0)-> m_editPID.SetWindowText (Display (int) iPID ));
    
CString strPath;
StrPath = getProcPath (iPID );
(CPage0 *) FromHandle (g_hPage0)-> m_editPATH.SetWindowText (strPath );
    
RECT rc;
: GetWindowRect (g_hWnd, & rc); // obtain the window rectangle.
CString strRect;
StrRect. format ("(% d, % d), (% d, % d) % dx % d", rc. left, rc. top, rc. right, rc. bottom,
Rc. right-rc.left, rc. bottom-rc.top );
(CPage0 *) FromHandle (g_hPage0)-> m_editRECT.SetWindowText (strRect );
GetProcPath is a function used to obtain the path of a process file. There are two methods to obtain the process path. In the NT system, we can use the OpenProcess () function to open the process, use the EnumProcessModules () function to enumerate the modules of the process, and finally use GetModuleFileNameEx () the function can obtain the path of the process. The second method is to use the relevant functions in the ToolHelp API. The latter is compatible with systems after Windows9x and NT4.0, so this method is adopted. Its implementation code is as follows:CString getProcPath(int PID)
{
  HANDLE hModule;
  MODULEENTRY32* minfo=new MODULEENTRY32;
  minfo->dwSize=sizeof(MODULEENTRY32);
  hModule=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,PID); Module32First(hModule,minfo);
  CString str;
  str.Format("%s",minfo->szExePath);
  CloseHandle(hModule);
  if(minfo) delete minfo;
  return str;  
}
  

5. Style Tab

The style tab is designed as follows:

  

The API function GetWindowLong can be used to obtain the values of window styles or extended styles. Then we will list all window styles starting with WS _ and the above style values for "bitwise AND" operations. If they are included, their window styles will be returned; otherwise, 0 will be returned. In this way, you can get a list of window styles. The extended style list is similar to the style list. The related code is as follows:

CListBox * pListStyle = (CListBox *) (CPage1 *) FromHandle (g_hPage1)-> GetDlgItem (IDC_LIST_STYLE ));
CListBox * pListExStyle = (CListBox *) (CPage1 *) FromHandle (g_hPage1)-> GetDlgItem (IDC_LIST_EX_STYLE ));
CEdit * pEditStyle = (CEdit *) (CPage1 *) FromHandle (g_hPage1)-> GetDlgItem (IDC_EDIT_STYLE ));
CEdit * pEditExStyle = (CEdit *) (CPage1 *) FromHandle (g_hPage1)-> GetDlgItem (IDC_EDIT_EX_STYLE ));
Long style = GetWindowLong (g_hWnd, GWL_STYLE );
Long styleEx = GetWindowLong (g_hWnd, GWL_EXSTYLE );
PEditStyle-> SetWindowText (Display (int) style ));
PEditExStyle-> SetWindowText (Display (int) styleEx ));
PListStyle-> ResetContent (); // clear the style list box
PListExStyle-> ResetContent (); // clear the extended style list box
If (style & WS_BORDER)
PListStyle-> AddString ("WS_BORDER ");
If (style & WS_CAPTION)
PListStyle-> AddString ("WS_CAPTION ");
If (style & WS_CHILD)
PListStyle-> AddString ("WS_CHILD ");
......
  

Vi. Category Tab

The design of the class tab is as follows:

  

The class name is obtained on the regular tab. The API function GetClassLong can be used to obtain the class style value. The style list is similar to the window style.

7. window tab

The design of the window tab is as follows:

  

On this page, the following API functions are used: GetNextWindow, GetWindow, and SendMessage. These three API functions can be used with different parameter values to implement different functions. The GetWIndowText function is not used here because it cannot retrieve the titles of some system windows and hidden windows. We replace the SendMessage function with the WM_GETTEXT parameter. The Code is as follows:

CPage3 * pPage3 = (CPage3 *) FromHandle (g_hPage3 );
HWND tempHandle;
Char tempstr [255] = "";
TempHandle = g_hWnd; // current window handle
PPage3-> SetDlgItemText (IDC_MYHWND, Display (int) tempHandle ));
// Obtain the title of this window
: SendMessage (tempHandle, WM_GETTEXT, 255, (LPARAM) tempstr );
PPage3-> SetDlgItemText (IDC_MYTITLE, tempstr );
// The previous window
TempHandle =: GetNextWindow (g_hWnd, GW_HWNDPREV );
PPage3-> SetDlgItemText (IDC_PREHWND, Display (int) tempHandle ));
// Obtain the title of the previous window
Memset (tempstr, 0,255 );
: SendMessage (tempHandle, WM_GETTEXT, 255, (LPARAM) tempstr );
PPage3-> SetDlgItemText (IDC_PRETITLE, tempstr );
// Next window
TempHandle =: GetNextWindow (g_hWnd, GW_HWNDNEXT );
Ppage3-> setdlgitemtext (idc_nexthwnd, display (INT) temphandle ));
Memset (tempstr, 0,255); // obtain the title of the next window
: Sendmessage (temphandle, wm_gettext, 255, (lparam) tempstr );
Ppage3-> setdlgitemtext (idc_nexttitle, tempstr );
    
Temphandle =: getparent (g_hwnd); // parent window
Ppage3-> setdlgitemtext (idc_parenthwnd, display (INT) temphandle ));
Memset (tempstr, 0,255 );
: Sendmessage (temphandle, wm_gettext, 255, (lparam) tempstr );
Ppage3-> setdlgitemtext (idc_parenttitle, tempstr );
// The first subwindow
Temphandle =: getwindow (g_hwnd, gw_child );
Ppage3-> setdlgitemtext (idc_childhwnd, display (INT) temphandle ));
Memset (tempstr,- 0,255 );
: Sendmessage (temphandle, wm_gettext, 255, (lparam) tempstr );
Ppage3-> setdlgitemtext (idc_childtitle, tempstr );
// Owner window
TempHandle =: GetWindow (g_hWnd, GW_OWNER );
Page3-> SetDlgItemText (IDC_OWNERHWND, Display (int) tempHandle ));
Memset (tempstr, 0,255 );
: SendMessage (tempHandle, WM_GETTEXT, 255, (LPARAM) tempstr );
PPage3-> SetDlgItemText (IDC_OWNERTITLE, tempstr );
  

8. Message Tab

The design of the message tab is as follows:

The list box on this page is different from the style list box. Each of its list items has a check box. This requires the class CCheckListBox. Here we will use subclass knowledge again. From the process of making CMyPric in the first section of this article, we realized the role of subclass and felt its inconvenience. Here, we use another method to generate the relevant code by using Class Wizard, and then modify it. First, draw a list control in the dialog box on this property page, Open Class Wizard and associate it with a CListBox Class variable m_listStatus. Set the Owner Draw attribute of the list box to Fixed and select its Has Strings option. For example:

      

Then, in Page4.h, find the definition CListBox m_listStatus of m_listStatus and change it to CCheckListBox m_listStatus. In this way, we can use all the functions of CCheckListBox.

In the dialog box initialization process, add the following statements to add the list items:

CCheckListBox * plistStatus = (CCheckListBox *) FromHandle (g_hPage4)-> GetDlgItem (IDC_LISTSTATUS ));
PlistStatus-> AddString ("window visible ");
PlistStatus-> AddString ("window available ");
PlistStatus-> AddString ("always at the beginning ");
PlistStatus-> AddString ("window read-only ");
PlistStatus-> AddString ("maximize ");
PlistStatus-> AddString ("minimal ");
PlistStatus-> AddString ("Restore window ");
PlistStatus-> AddString ("Close Window ");
PlistStatus-> AddString ("activation window ");
Next, we need to determine which list items are checked when the window/control is selected. This judgment process is similar to the implementation of the style list. The Code is as follows:long style = GetWindowLong(g_hWnd, GWL_STYLE);
if( style & WS_VISIBLE )
{
  pListStatus->SetCheck(0,1);
}
For other items, see source code. The function of this list box is not only to display the window status, but also to change the window status or stimulate its behavior when you check the changes. The message for checking the status change is LBN_SELCHANGE. In addition, in order not to make a check change, all the list items are stimulated. We use the switch structure so that the list item is selected and the list item is inspired. The Code is as follows:void CPage4::OnSelchangeListstatus()
{
  // TODO: Add your control notification handler code here
  int n=m_listStatus.GetCurSel();
  switch(n)
  {
  case 0:
    if(m_listStatus.GetCheck(0)== 1 )
      ::ShowWindow(g_hWnd, SW_SHOW);
    else
      ::ShowWindow(g_hWnd, SW_HIDE);
    break;
  case 1:
    if(m_listStatus.GetCheck(1) == 1)
      ::EnableWindow(g_hWnd, TRUE);
    else
      ::EnableWindow(g_hWnd,FALSE);
    break;
  case 2:
    if(m_listStatus.GetCheck(2) == 1)
      ::SetWindowPos(g_hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
    else
      ::SetWindowPos(g_hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
    break;
  case 3:
    if(m_listStatus.GetCheck(3) == 1)
      ::SendMessage(g_hWnd, EM_SETREADONLY, TRUE, 0);
    else
      ::SendMessage(g_hWnd, EM_SETREADONLY, FALSE, 0);
    break;
  case 4:
    if(m_listStatus.GetCheck(4) ==1)
    {
      ::ShowWindow(g_hWnd, SW_MAXIMIZE);
      m_listStatus.SetCheck(5,0);
    }
    else
      ::ShowWindow (g_hWnd, SW_RESTORE);
    break;
  case 5:
    if (m_listStatus.GetCheck(5) == 1)
    {
      ::ShowWindow(g_hWnd, SW_MINIMIZE);
      m_listStatus.SetCheck(4,0);
    }
    else
      ::ShowWindow(g_hWnd, SW_RESTORE);
    break;
  case 6:
    if(m_listStatus.GetCheck(6) ==1)
    {
      ::ShowWindow (g_hWnd, SW_RESTORE);
      m_listStatus.SetCheck(6,0);
      m_listStatus.SetCheck(5,0);
      m_listStatus.SetCheck(4,0);
    }
    break;
  case 7:
    if(m_listStatus.GetCheck(7) ==1)
    {
      ::SendMessage (g_hWnd, WM_CLOSE, 0, 0);
      m_listStatus.SetCheck(7,0);
    }
    break;
  case 8:
    if(m_listStatus.GetCheck(8) ==1)
    {
      ::BringWindowToTop(g_hWnd);
      m_listStatus.SetCheck(8,0);
    }
    break;
  default:
  ;
  }
}
Spy ++ has been created. Looking back on the process, there are not many difficulties, and there are many issues in detail. It is inevitable that we should not only look like it, but also look like it. There must be a lot of incomplete information in this article, and I hope that my colleagues will not be enlightened. The code is successfully debugged in Window XP + vc6.0. The spy ++ source code is also put here.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.