#include "stdafx.h"
#include "PwdSpy.h"
#include "PwdSpyDlg.h"
#include "HyperLink.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Register our Window Message
// This message is passed to us if the user tries to active multiple copies of the app
UINT CPwdSpyDlg::s_wmActivateApp = RegisterWindowMessage(g_szCustomWndMsg);
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
CHyperLink m_ctrlHyperLink;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange *pDX);
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//***********************************************
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
//***********************************************
void CAboutDlg::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
DDX_Control(pDX, IDC_STATIC_URL, m_ctrlHyperLink);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//***********************************************
CPwdSpyDlg::CPwdSpyDlg(CWnd *pParent)
: CDialog(CPwdSpyDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CPwdSpyDlg)
//}}AFX_DATA_INIT
// Load the icons and cursors
m_hIconLarge = (HICON)LoadImage(AfxGetApp()->m_hInstance,
MAKEINTRESOURCE(IDR_MAINFRAME),
IMAGE_ICON,
GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CYICON),
0);
m_hIconSmall = (HICON)LoadImage(AfxGetApp()->m_hInstance,
MAKEINTRESOURCE(IDR_MAINFRAME),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0);
m_hIconBlank = (HICON)LoadImage(AfxGetApp()->m_hInstance,
MAKEINTRESOURCE(IDI_BLANK_ICON),
IMAGE_ICON,
GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CXICON),
0);
m_hIconScan = (HICON)LoadImage(AfxGetApp()->m_hInstance,
MAKEINTRESOURCE(IDI_LOOK_ICON),
IMAGE_ICON,
GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CXICON),
0);
m_hCursorScan = (HCURSOR)LoadImage(AfxGetApp()->m_hInstance,
MAKEINTRESOURCE(IDC_LOOK_CUR),
IMAGE_CURSOR,
GetSystemMetrics(SM_CXCURSOR),
GetSystemMetrics(SM_CXCURSOR),
0);
m_hCursorPrev = NULL;
m_hWndPrev = m_hWndScanEx = NULL;
m_bIsLooking = false;
m_bAlwaysOnTop = true;
m_nScanLevel = 0;
// Use ScanEx if Win2000/XP/2003
m_bScanEx = (m_osi.IsNT() && m_osi.GetMajor() >= 5) ? true : false;
m_wndPopupTip.Create(this);
}
//***********************************************
CPwdSpyDlg::~CPwdSpyDlg()
{
if(m_hIconLarge != NULL) DestroyIcon(m_hIconLarge);
if(m_hIconSmall != NULL) DestroyIcon(m_hIconSmall);
if(m_hIconBlank != NULL) DestroyIcon(m_hIconBlank);
if(m_hIconScan != NULL) DestroyIcon(m_hIconScan);
if(m_hCursorScan != NULL) DestroyCursor(m_hCursorScan);
}
//***********************************************
void CPwdSpyDlg::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPwdSpyDlg)
DDX_Control(pDX, IDC_LOOK, m_ctrlLook);
DDX_Text(pDX, IDC_EDIT_MOUSEPOS, m_strMousePos);
DDX_Text(pDX, IDC_EDIT_HWND, m_strHwnd);
DDX_Text(pDX, IDC_EDIT_CAPTION, m_strCaption);
DDX_Text(pDX, IDC_EDIT_WNDCLASS, m_strWndClass);
DDX_Text(pDX, IDC_EDIT_ISPWD, m_strIsPwd);
DDX_Text(pDX, IDC_EDIT_PWD, m_strPwd);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPwdSpyDlg, CDialog)
//{{AFX_MSG_MAP(CPwdSpyDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_COPYDATA()
//}}AFX_MSG_MAP
ON_REGISTERED_MESSAGE(s_wmActivateApp, OnActivateApp)
END_MESSAGE_MAP()
//***********************************************
BOOL CPwdSpyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// IDM_ALWAYS_ON_TOP must be in the system command range.
_ASSERTE((IDM_ALWAYS_ON_TOP & 0xFFF0) == IDM_ALWAYS_ON_TOP);
_ASSERTE(IDM_ALWAYS_ON_TOP < 0xF000);
// IDM_ABOUTBOX must be in the system command range.
_ASSERTE((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
_ASSERTE(IDM_ABOUTBOX < 0xF000);
CMenu *pSysMenu = GetSystemMenu(FALSE);
if(pSysMenu != NULL)
{
// Remove the "Size" and "Maximize" menu options from the system menu
pSysMenu->DeleteMenu(SC_SIZE, MF_BYCOMMAND);
pSysMenu->DeleteMenu(SC_MAXIMIZE, MF_BYCOMMAND);
// Append a separator, Always On Top, and About
CString strMenu;
pSysMenu->AppendMenu(MF_SEPARATOR);
strMenu.LoadString(IDS_ALWAYS_ON_TOP); _ASSERTE(!strMenu.IsEmpty());
pSysMenu->AppendMenu(MF_STRING, IDM_ALWAYS_ON_TOP, strMenu);
strMenu.LoadString(IDS_ABOUTBOX); _ASSERTE(!strMenu.IsEmpty());
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strMenu);
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIconLarge, TRUE); // Set big icon
SetIcon(m_hIconSmall, FALSE); // Set small icon
((CComboBox*)GetDlgItem(IDC_COMBO_LEVEL))->SetCurSel(m_nScanLevel);
OnAlwaysOnTop();
return TRUE;
}
//***********************************************
void CPwdSpyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if((nID & 0xFFF0) == IDM_ALWAYS_ON_TOP)
{
m_bAlwaysOnTop ^= true;
OnAlwaysOnTop();
}
else if((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
//***********************************************
void CPwdSpyDlg::OnPaint()
{
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
if(IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIconLarge);
}
else
{
CDialog::OnPaint();
}
}
//***********************************************
HCURSOR CPwdSpyDlg::OnQueryDragIcon()
{
// The system calls this to obtain the cursor to display
// while the user drags the minimized window.
return (HCURSOR)m_hIconSmall;
}
//***********************************************
void CPwdSpyDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd *pWnd = ChildWindowFromPoint(point);
if(pWnd != NULL && pWnd->GetSafeHwnd() == m_ctrlLook.GetSafeHwnd())
StartLooking();
CDialog::OnLButtonDown(nFlags, point);
}
//***********************************************
void CPwdSpyDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_bIsLooking)
StopLooking();
CDialog::OnLButtonUp(nFlags, point);
}
//***********************************************
void CPwdSpyDlg::StartLooking(void)
{
m_nScanLevel = ((CComboBox*)GetDlgItem(IDC_COMBO_LEVEL))->GetCurSel();
if(m_nScanLevel == CB_ERR) m_nScanLevel = 0;
SetCapture();
m_bIsLooking = true;
m_hCursorPrev = SetCursor(m_hCursorScan);
m_ctrlLook.SetIcon(m_hIconBlank);
}
//***********************************************
void CPwdSpyDlg::StopLooking(void)
{
ReleaseCapture();
m_bIsLooking = false;
// If we've hooked another process, remove the hook
if(m_bScanEx)
RemoveHook();
m_wndPopupTip.HidePopupWindow();
if(m_hWndPrev != NULL)
{
InvertBorder(m_hWndPrev);
m_hWndPrev = NULL;
}
// SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
SetCursor(m_hCursorPrev);
m_ctrlLook.SetIcon(m_hIconScan);
// Redraw the whole screen
::InvalidateRect(NULL, NULL, FALSE);
}
//***********************************************
void CPwdSpyDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_bIsLooking)
Scan(point);
CDialog::OnMouseMove(nFlags, point);
}
//***********************************************
void CPwdSpyDlg::Scan(CPoint point)
{
// The Scan function scans the given point for a window
// and extracts the password, if there is one. The Scan
// function works differently for Win95/98/ME and NT4
// versus Win2000/XP/2003.
_ASSERTE(m_bIsLooking);
bool bFound = false;
ClientToScreen(&point);
m_strMousePos.Format(_T("X=%ld, Y=%ld"), point.x, point.y);
m_strHwnd.Empty();
m_strCaption.Empty();
m_strWndClass.Empty();
m_strIsPwd.Empty();
m_strPwd.Empty();
HWND hWnd;
// hWnd = ::WindowFromPoint(point);
hWnd = SmallestWindowFromPoint(point);
if(hWnd != NULL)
{
// Make sure that the window doesn't belong to us
if(GetWindowThreadProcessId(GetSafeHwnd(), NULL) != GetWindowThreadProcessId(hWnd, NULL))
{
if(hWnd != m_hWndPrev)
{ // New window, remove the old border and draw a new one
m_wndPopupTip.HidePopupWindow();
InvertBorder(m_hWndPrev);
m_hWndPrev = hWnd;
InvertBorder(m_hWndPrev);
}
TCHAR szBuffer[256];
m_strHwnd.Format(_T("0x%08X"), hWnd);
m_strIsPwd.LoadString((m_nScanLevel == 2) ? IDS_NOT_AVAILABLE : IDS_NO);
// Get the caption
if(::GetWindowText(hWnd, szBuffer, sizeof(szBuffer) / sizeof(TCHAR)))
m_strCaption = szBuffer;
// Get the class name
if(::GetClassName(hWnd, szBuffer, sizeof(szBuffer) / sizeof(TCHAR)))
m_strWndClass = szBuffer;
if(m_nScanLevel >= 1 || m_strWndClass.CompareNoCase(_T("edit")) == 0)
{
// Get the window's style
long nStyle = ::GetWindowLong(hWnd, GWL_STYLE);
if(m_nScanLevel == 2 || nStyle & ES_PASSWORD)
{
CRect rect; ::GetWindowRect(hWnd, &rect);
if(m_nScanLevel == 0) m_strIsPwd.LoadString(IDS_YES);
if(m_nScanLevel == 1) m_strIsPwd.LoadString(IDS_MAYBE);
bFound = true;
// Here is where the actual scanning for the password is done.
// If the OS is Win95/98/ME or NT4 we can simply ask the control.
// If the OS is Win2000/XP/2003 we must hook the process to
// extract the password.
if(m_bScanEx)
{ // Win2000/XP/2003
if(InstallHook(GetWindowThreadProcessId(hWnd, NULL)))
{
if(ScanPassword(hWnd, GetSafeHwnd()))
m_hWndScanEx = hWnd, m_ptScanEx = point;
}
}
else
{ // Win95/98/ME or WinNT
*szBuffer = _T('\0');
::SendMessage(hWnd, WM_GETTEXT, sizeof(szBuffer) / sizeof(TCHAR), (LPARAM)szBuffer);
m_strPwd = szBuffer;
m_wndPopupTip.ShowPopupWindow(m_strPwd, point, rect);
}
}
}
}
else
{ // The window belongs to us, remove the old border
m_wndPopupTip.HidePopupWindow();
InvertBorder(m_hWndPrev);
m_hWndPrev = NULL;
}
}
if(!bFound)
m_wndPopupTip.HidePopupWindow();
UpdateData(FALSE);
}
//***********************************************
void CPwdSpyDlg::OnAlwaysOnTop()
{
::SetWindowPos(GetSafeHwnd(), (m_bAlwaysOnTop) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
// Check/uncheck the menu item
CMenu *pSysMenu = GetSystemMenu(FALSE);
if(pSysMenu != NULL)
{
UINT nFlags = MF_BYCOMMAND | ((m_bAlwaysOnTop) ? MF_CHECKED : MF_UNCHECKED);
pSysMenu->CheckMenuItem(IDM_ALWAYS_ON_TOP, nFlags);
}
}
//***********************************************
BOOL CPwdSpyDlg::PreTranslateMessage(MSG *pMsg)
{
if(pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE && m_bIsLooking)
{
StopLooking();
return TRUE;
}
else
{
return CDialog::PreTranslateMessage(pMsg);
}
}
//***********************************************
HWND CPwdSpyDlg::SmallestWindowFromPoint(const POINT &point)
{
// Find the smallest "window" still containing the point
// Doing this prevents us from stopping at the first window containing the point
RECT rect, rectSearch;
HWND hParentWnd, hWnd, hSearchWnd;
hWnd = ::WindowFromPoint(point);
if(hWnd != NULL)
{
// Get the size and parent for compare later
::GetWindowRect(hWnd, &rect);
hParentWnd = ::GetParent(hWnd);
// We only search further if the window has a parent
if(hParentWnd != NULL)
{
// Search from the window down in the Z-Order
hSearchWnd = hWnd;
do{
hSearchWnd = ::GetWindow(hSearchWnd, GW_HWNDNEXT);
// Does the search window also contain the point, have the same parent, and is visible?
::GetWindowRect(hSearchWnd, &rectSearch);
if(::PtInRect(&rectSearch, point) && ::GetParent(hSearchWnd) == hParentWnd && ::IsWindowVisible(hSearchWnd))
{
// It does, but is it smaller?
if(((rectSearch.right - rectSearch.left) * (rectSearch.bottom - rectSearch.top)) < ((rect.right - rect.left) * (rect.bottom - rect.top)))
{
// Found new smaller window, update compare window
hWnd = hSearchWnd;
::GetWindowRect(hWnd, &rect);
}
}
}while(hSearchWnd != NULL);
}
}
return hWnd;
}
//***********************************************
void CPwdSpyDlg::InvertBorder(const HWND hWnd)
{
if(!IsWindow(hWnd))
return;
RECT rect;
// Get the coordinates of the window on the screen
::GetWindowRect(hWnd, &rect);
// Get a handle to the window's device context
HDC hDC = ::GetWindowDC(hWnd);
// Create an inverse pen that is the size of the window border
SetROP2(hDC, R2_NOT);
HPEN hPen = CreatePen(PS_INSIDEFRAME, 3 * GetSystemMetrics(SM_CXBORDER), RGB(0,0,0));
// Draw the rectangle around the window
HPEN hOldPen = (HPEN)SelectObject(hDC, hPen);
HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, GetStockObject(NULL_BRUSH));
Rectangle(hDC, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
SelectObject(hDC, hOldBrush);
SelectObject(hDC, hOldPen);
// Give the window its device context back, and destroy our pen
::ReleaseDC(hWnd, hDC);
DeleteObject(hPen);
}
//***********************************************
LRESULT CPwdSpyDlg::OnActivateApp(WPARAM wParam, LPARAM lParam)
{
if(!IsWindowVisible()) ShowWindow(SW_SHOW);
if(IsIconic()) ShowWindow(SW_RESTORE);
SetForegroundWindow();
return TRUE;
}
//***********************************************
BOOL CPwdSpyDlg::OnCopyData(CWnd *pWnd, COPYDATASTRUCT *pCopyDataStruct)
{
try
{
if((HWND)pCopyDataStruct->dwData == m_hWndScanEx)
{
TCHAR szBuffer[256] = {_T('\0')};
DWORD dwSize = sizeof(szBuffer) * sizeof(TCHAR);
if(pCopyDataStruct->cbData < dwSize)
dwSize = pCopyDataStruct->cbData;
CopyMemory(szBuffer, pCopyDataStruct->lpData, dwSize);
m_strPwd = szBuffer;
CRect rect; ::GetWindowRect(m_hWndScanEx, &rect);
m_wndPopupTip.ShowPopupWindow(m_strPwd, m_ptScanEx, rect);
UpdateData(FALSE);
}
}
catch(...) {}
return TRUE;
}