Introduction
Monitoring applications can be used for Parental Control or just as a safe guard for your own computer, while you are away. It can be helpful to even find out what you have done, deleted text, etc.
Background
The purpose of this project is to create a small application which will run in the background and capture screenshots periodically along with the text typed. Pressing ALT+U terminates it. Plain and simple.
The CConsoleWindow class
The purpose of this class is to allow dumping text such as trace calls into a console window.
typedef enum {
endl }ConsoleWndConstant;
class CConsoleWnd
{
HANDLE m_hConsoleWnd;
public:
CConsoleWnd();
const CConsoleWnd& operator<<(ConsoleWndConstant nConstant) const;
const CConsoleWnd& operator<<(LPCSTR lpsz) const;
const CConsoleWnd& operator<<(LPCWSTR lpsz) const;
const CConsoleWnd& operator<<(int nNum) const;
const CConsoleWnd& operator<<(unsigned long lNum) const;
const CConsoleWnd& operator<<(__int64 nNum) const;
const CConsoleWnd& operator<<(unsigned __int64 uNum) const;
const CConsoleWnd& operator<<(double dNum) const;
const CConsoleWnd& operator<<(float fNum) const;
const CConsoleWnd& operator<<(const void* ptr) const;
const CConsoleWnd& operator<<(TCHAR tChar) const;
};
The CMouseTracker class
This class handles grabbing data from the mouse but initiate the capture of screens.
class CMouseTracker
<pre>{
BOOL m_bIsRunning;
public:
int m_xPos;
int m_yPos;
UINT m_uLastMsg;
public:
CMouseTracker();
void Start();
void Stop();
};
The ScreenSnapshot class
This class handles capturing the screens which includes also the place of the mouse cursor.
class CScreenSnapshot
<pre>{
DWORD m_dwAddEntity;
int m_nImageQuality;
CString m_strUserName;
CString m_strComputerName;
TCHAR m_szActiveAppName[100];
CBitmap m_bmpResult;
public:
CImageList m_ImageListSingle;
public:
CScreenSnapshot();
CScreenSnapshot(DWORD dwAddEntity, int nImageQuality);
void operator=(const CScreenSnapshot& ScreenSnapshot);
enum AddEntity {
addUserName = 0x00000002,
addComputerName = 0x00000004,
addActiveAppName = 0x00000008,
addAll = 0xFFFFFFFF
};
void Snapshot(const SCREENSHOT_INFO* pScreenshotInfo);
};
Handling Bitmaps using CBitMap
This CBitMap class handles all functionalists and manipulations on bitmaps including saving them as a .bmp file.
class CBitmap
{
HBITMAP m_hBitmap;
public:
CBitmap();
CBitmap(HBITMAP hbmp);
operator HBITMAP() const;
void CreateCompatible(HDC hDC, int nWidth, int nHeight);
void Stretch(int nDesiredWidth, int nDesiredHeight);
void Copy(HBITMAP hbmp);
BOOL Compare(HBITMAP hbmp);
void CreateMask(HBITMAP hbmp);
void SaveToFile(LPCWSTR lpszFileName, int nQuality = 10) const;
void Delete();
};
Handling Hotwords via CHotwords
The CHotwords class is used to define how hot words are treated. A hot word is a sequence of keys which triggers an action as a result of being typed. For example, typing "quit" will quit the application.
class CHotwords
{
CString m_strHotwords;
CHotwordEvent* m_pHotwordEvents;
public:
int m_nCount;
public:
CHotwords();
CHotwords(const CHotwords& src);
void operator=(const CHotwords& src);
CString GetHotwords() const;
void Add(LPCTSTR lpszHotword, const CHotwordEvent& HotwordEvent);
~CHotwords();
friend class CKeyRecorder;
};
There could be other triggers which will follow a certain key word. In this demonstration, (and please be careful when using it...), typing "reboot" anywhere, will reboot your PC!
Recording keystrokes via CKeyRecorder
The CKeyRecorder class is used to capture keystrokes and convert them to their correct character based on the current key-map. That way, if a user uses a multilingual keyboard, such as Hebrew-English, and the same key can means different characters, the class will know to which character to convert it.
class CKeyRecorder
{
public:
CHotwords m_Hotwords;
static DWORD s_dwCatchHotwordsThreadId;
static DWORD s_dwRecorderThreadId;
static DWORD s_dwHandleHotwordThreadId;
static BOOL s_bIsRunning;
static HHOOK s_hKeyHook;
static HANDLE s_hFile;
static HWND s_hWndMainWnd;
public:
CKeyRecorder();
CKeyRecorder(const CHotwords& Hotwords);
void operator=(const CKeyRecorder& KeyRecorder);
void Start(HWND hWndMainWnd);
void Stop();
const CHotwordEvent* GetHotwordEvent(int nIndex) const;
friend class CLocalQuota;
friend class CDataSender;
};
There are two additional classes used in conjunction with other classes which takes care of two tasks:
1. Maintaining a Quota, to prevent overloading the monitored computer with too much data, taking care of various scenarios such as what to do when quota is reached, and what to do if afterward, the quota is released and there is free space, etc. All of the above is done via CLocalQuota
2. Taking care of transmitting data to a server, or via email or using any other way. That is done via another class named CDataSender.
These 2 aren't covered in the scope of this article.
ATL / MFC alternative
You will find in this source code a complete replacement of many of the ATL or MFC classes. That can be a nightmare in many cases as it is not advised to reinvent the wheel, but in this case, these were tested, debugged and fixed for around a year and the advantage is speed and compact side, as you don't have to link or use MFC DLL or static library, and same goes with ATL.
Tracing via WriteToLog
A while ago I have developed this small routine which is very useful for tracing and logging activities and errors. It is used like printf or TRACE and saves the output into one continuous file.
void WriteToLog(LPCTSTR lpText, ...)
{
FILE* file;
CTime time = CTime::ApiGetCurrentLocalTime();
CString strMsg;
va_list ptr;
va_start(ptr, lpText);
strMsg.VFormat(lpText, ptr);
CString strDate = time.FormatDate(_T("d/MM/yyyy"));
CString strTime = time.FormatTime(_T("hh:mm:ss tt"));
CString strTrace;
strTrace.Format(_T("%s %s: %s"), (LPCTSTR)strTime, (LPCTSTR)strDate, (LPCTSTR)strMsg);
file = _tfopen(LOG_FILENAME, L"a");
if (file)
{
_ftprintf(file, _T("\n%s\n"), (LPCTSTR)strTrace);
fclose(file);
}
}
Handling captured screens via CImageList
CImageList is a class developed as part of this project which can be used to maintain a list of image files, allowing each file to be moved, removed, added, and obtained.
class CImageList
{
HIMAGELIST m_hImageList;
public:
CImageList();
CImageList(HIMAGELIST hImageList);
CImageList(WORD ID, UINT cxImage, COLORREF clrMask,
UINT uGrowCount = 0);
CImageList(LPCTSTR lpszFileName, UINT cxImage,
COLORREF clrMask, UINT uGrowCount = 0);
operator HIMAGELIST() const;
void operator=(HIMAGELIST hImageList);
enum ImageListFlags {
ilColor = ILC_COLOR,
ilColor4 = ILC_COLOR4,
ilColor8 = ILC_COLOR8,
ilColor16 = ILC_COLOR16,
ilColor24 = ILC_COLOR24,
ilColor32 = ILC_COLOR32,
ilColorDDB = ILC_COLORDDB,
ilMask = ILC_MASK,
};
enum ColorFlag {
colorNone = CLR_NONE,
colorDefault = CLR_DEFAULT
};
BOOL Create(DWORD dwImageListFlags, UINT cxImage,
UINT cyImage, UINT uImagesCount, UINT uGrowCount = 0);
BOOL Load(WORD ID, UINT cxImage, COLORREF clrMask,
UINT uGrowCount = 0);
BOOL Load(LPCTSTR lpszFileName, UINT cxImage,
COLORREF clrMask, UINT uGrowCount = 0);
int Add(HICON hIcon);
int Add(HBITMAP hbmpImage, HBITMAP hbmpMask);
int Add(HBITMAP hbmpImage, COLORREF clrMask);
BOOL Replace(int nImageIndex, HBITMAP hbmpImage, HBITMAP hbmpMask);
BOOL Replace(int nImageIndex, HICON hIcon);
BOOL Remove(int nImageIndex);
BOOL Empty();
BOOL Copy(int nDstImageIndex, HIMAGELIST hSrcImageList, int nSrcImageIndex);
BOOL Swap(int nDstImageIndex, HIMAGELIST hSrcImageList, int nSrcImageIndex);
int GetImageCount() const;
BOOL GetImageInfo(int nImageIndex, IMAGEINFO* pii) const;
enum DrawStyle {
drawBlend25 = ILD_BLEND25,
drawBlend50 = ILD_BLEND50,
drawMask = ILD_MASK,
drawNormal = ILD_NORMAL,
drawTransparent = ILD_TRANSPARENT,
};
COLORREF SetBkColor(COLORREF clrBk);
COLORREF GetBkColor() const;
BOOL Draw(HDC hdcDst, int nImageIndex,
const POINT& pt,
DWORD dwDrawStyle
) const;
BOOL DrawEx(HDC hdcDst, int nImageIndex,
const POINT& pt,
const SIZE& size,
COLORREF clrBk,
COLORREF clrFg,
DWORD dwDrawStyle
) const;
HIMAGELIST Duplicate() const;
BOOL Destroy();
};
More details to come...
Michael Haephrati, born in 1964, an entrepreneur, inventor and a musician. Haephrati worked on many ventures starting from HarmonySoft, designing Rashumon, the first Graphical Multi-lingual word processor for Amiga computer.
Worked with Amdocs and managed several software projects, among them one for the Ministry of Tourism in New Zealand. During 1995-1996 he worked as a Contractor with Apple at Cupertino. After returning to Israel, worked as a Project Manager with Top Image Systems (mostly with JCC, Nicosia), and then at a research institute made the fist steps developing the credit scoring field in Israel. He founded Target Scoring and developed a credit scoring system named ThiS, based on geographical statistical data, participating VISA CAL, Isracard, Bank Leumi and Bank Discount (Target Scoring, being the VP Business Development of a large Israeli institute).
During 2000, he founded Target Eye, and developed the first remote PC surveillance and monitoring system, named Target Eye.
Other ventures included: Data Cleansing (as part of the DataTune system which was implemented in many organizations.
Also a Code Project Member since Sunday, March 16, 2003 (10 years, 5 months)
20 Sep 2013: Best C++ article of August 2013
25 Jan 2013: Code Project - Best C++ article of December 2012
31 Dec 2012: CodeProject MVP 2013