最近学了些关于window api编程的知识,于是琢磨编写一些键盘记录器,能够把输入的按键输出到窗口内,并且实现窗口自动滚动。

封装窗口类使用了GWL_USERDATA字段来保存this指针,比较容易理解,缺点如果程序别的地方使用这个字段会引起崩溃...

WinClassBase.h

#ifndef _WINDOW_CLASS_BASE_
#define _WINDOW_CLASS_BASE_ #include <windows.h>
#include <vector>
#include <string> class WinClassBase
{
public:
WinClassBase(HINSTANCE hInastance, HWND HwndParent = NULL, int winLeft=, int winRight=, int winTop=, int winBottom=);
~WinClassBase(); virtual int HandleMessage(UINT message,WPARAM wParam,LPARAM lParam) = ;
virtual LPCTSTR GetMyClassName() = ; //创建窗口
void Create();
//获取窗口句柄
HWND GetMyHandle() const { return m_hWnd; } void ShowWindow(int nShowCmd);
int exec(); protected:
virtual UINT GetMyClassStyle() { return CS_VREDRAW | CS_HREDRAW; }
virtual HICON GetMyClassIcon() { return NULL; }
virtual HCURSOR GetMyClassCursor() { return NULL; }
virtual HBRUSH GetMyClassBackground() { return HBRUSH(COLOR_WINDOW+); }
virtual LPCTSTR GetMyClassMenuName() { return NULL; } virtual LPCTSTR GetMyWindowName() { return TEXT("wuyou"); }
virtual DWORD GetMyWindowStyle() { return WS_OVERLAPPEDWINDOW; }
virtual HMENU GetMyWindowMenu() { return NULL; }
private:
//原始窗口
static LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam); protected:
HWND m_hWnd;
HWND m_hWndParent;
RECT m_rect;
HINSTANCE m_hInastance; //已注册过的类的集合
static std::vector<std::wstring> registeredClassArray;
}; #endif //_WINDOW_CLASS_BASE_

WinClassBase.cpp

#include "WinClassBase.h"

std::vector<std::wstring> WinClassBase::registeredClassArray;  

WinClassBase::WinClassBase(HINSTANCE hInastance, HWND hWndParent, int winLeft, int winRight, int winTop, int winBottom)
{
m_hInastance = hInastance; m_hWndParent = hWndParent; m_rect.left = winLeft;
m_rect.right = winRight;
m_rect.top = winTop;
m_rect.bottom = winBottom; m_hWnd = NULL;
} WinClassBase::~WinClassBase(void)
{
if( this->m_hWnd != NULL && ::IsWindow(this->m_hWnd) )
{
::DestroyWindow(this->m_hWnd);
}
} //创建窗口
void WinClassBase::Create()
{
unsigned int i=;
for(i=; i<registeredClassArray.size(); ++i)
{
if( registeredClassArray[i] == std::wstring(this->GetMyClassName()) )
{
break;
}
} //注册
if( i == registeredClassArray.size() )
{
WNDCLASS win; win.cbClsExtra = ;
win.cbWndExtra = ;
win.hbrBackground = this->GetMyClassBackground();
win.hCursor = this->GetMyClassCursor();
win.hIcon = this->GetMyClassIcon();
win.hInstance = m_hInastance;
win.lpfnWndProc = WinClassBase::WindowProc;
win.lpszClassName = this->GetMyClassName();
win.lpszMenuName = this->GetMyClassMenuName();
win.style = this->GetMyClassStyle(); if( != ::RegisterClass(&win))
{
registeredClassArray.push_back(this->GetMyClassName());
}
} //创建窗口
if( NULL == this->m_hWnd )
{
HWND hWnd = ::CreateWindow(this->GetMyClassName(),
this->GetMyWindowName(),
this->GetMyWindowStyle(),
this->m_rect.left,
this->m_rect.top,
this->m_rect.right - this->m_rect.left,
this->m_rect.bottom - this->m_rect.top,
this->m_hWndParent,
this->GetMyWindowMenu(),
this->m_hInastance,
(LPVOID)this
); if(NULL == hWnd)
{
this->m_hWnd = NULL;
WCHAR errorMsg[] = {};
::swprintf(errorMsg, , TEXT("CreateWindow Failed: %ld"), ::GetLastError());
::MessageBox(NULL, errorMsg, TEXT("Error"), MB_OK);
return ;
}
}
} LRESULT CALLBACK WinClassBase::WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
WinClassBase *pThis = NULL; if(message == WM_CREATE)
{
pThis = (WinClassBase *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
pThis->m_hWnd = hwnd;
::SetWindowLong(hwnd, GWL_USERDATA, (LONG)pThis);
} pThis = (WinClassBase *)::GetWindowLong(hwnd, GWL_USERDATA); switch(message)
{
case WM_DESTROY:
PostQuitMessage();
break;
default:
if(pThis != NULL && pThis->HandleMessage(message, wParam, lParam) == )
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
else if(pThis == NULL)
{
return DefWindowProc(hwnd, message, wParam, lParam);
} break;
} return ;
} void WinClassBase::ShowWindow(int nShowCmd)
{
::ShowWindow(this->m_hWnd, nShowCmd);
::UpdateWindow(this->m_hWnd);
}
int WinClassBase::exec()
{
MSG msg; while(::GetMessage(&msg, NULL, NULL, NULL))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
} return ;
}

KeyBoard.h

#pragma once

#include "WinClassBase.h"

#define MAX_LINE 1000

class KeyBoard : public WinClassBase
{
public:
KeyBoard(HINSTANCE hInastance, HWND HwndParent = NULL, int winLeft=, int winRight=, int winTop=, int winBottom=);
~KeyBoard(void); virtual int HandleMessage(UINT message,WPARAM wParam,LPARAM lParam);
virtual LPCTSTR GetMyClassName(); virtual DWORD GetMyWindowStyle() { return WS_OVERLAPPEDWINDOW | WS_VSCROLL; }
virtual LPCTSTR GetMyWindowName() { return TEXT("键盘记录"); } private:
int m_line;
TEXTMETRIC m_textMetric;
SCROLLINFO m_scrollinfo; TCHAR m_charArray[MAX_LINE][];
};

KeyBoard.cpp

#include "KeyBoard.h"
#include <wchar.h> KeyBoard::KeyBoard(HINSTANCE hInastance, HWND hWndParent, int winLeft, int winRight, int winTop, int winBottom)
:WinClassBase(hInastance, hWndParent, winLeft, winRight, winTop, winBottom)
{
} KeyBoard::~KeyBoard(void)
{
} int KeyBoard::HandleMessage(UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
{
HDC hdc = GetDC(m_hWnd);
::GetTextMetrics(hdc, &m_textMetric);
ReleaseDC(m_hWnd, hdc);
m_scrollinfo.cbSize = sizeof(m_scrollinfo);
m_scrollinfo.nMax = MAX_LINE - ;
m_scrollinfo.nMin = ;
m_scrollinfo.nPos = ;
m_line = ; return ;
}
case WM_SIZE:
{
WORD newHeight = HIWORD(lParam);
m_scrollinfo.nPage = newHeight / m_textMetric.tmHeight;
m_scrollinfo.fMask = SIF_ALL;
::SetScrollInfo(m_hWnd, SB_VERT, &m_scrollinfo, TRUE); return ;
}
case WM_VSCROLL:
{
switch(LOWORD(wParam))
{
case SB_BOTTOM:
m_scrollinfo.nPos = m_line;
break;
case SB_LINEDOWN:
m_scrollinfo.nPos = (m_scrollinfo.nPos+);
break;
case SB_LINEUP:
if( m_scrollinfo.nPos >= )
m_scrollinfo.nPos = m_scrollinfo.nPos-;
break;
case SB_PAGEDOWN:
m_scrollinfo.nPos += m_scrollinfo.nPage;
break;
case SB_PAGEUP:
m_scrollinfo.nPos -= m_scrollinfo.nPage;
break;
case SB_THUMBPOSITION:
m_scrollinfo.nPos = HIWORD(wParam);
break;
case SB_THUMBTRACK:
m_scrollinfo.nPos = HIWORD(wParam);
break;
} m_scrollinfo.fMask = SIF_POS;
SetScrollInfo(m_hWnd, SB_VERT, &m_scrollinfo, TRUE);
InvalidateRect(m_hWnd, NULL, TRUE); return ;
}
case WM_CHAR:
{
if(m_line < MAX_LINE)
{
wmemset(m_charArray[m_line], , );
swprintf(m_charArray[m_line], , TEXT("wParam = 0x%X lParam = 0x%X val = %c"), wParam, lParam, wParam);
m_line ++; if(m_line >= (int)(m_scrollinfo.nPos + m_scrollinfo.nPage))
::PostMessage(m_hWnd, WM_VSCROLL, SB_PAGEDOWN, );
else
{
RECT rect;
rect.left = ;
rect.right = m_rect.right;
rect.top = ((m_line-) % m_scrollinfo.nPage) * m_textMetric.tmHeight;
rect.bottom = rect.top + m_textMetric.tmHeight;
InvalidateRect(m_hWnd, &rect, TRUE);
}
} return ;
}
case WM_PAINT:
{
PAINTSTRUCT paint;
HDC hdc = ::BeginPaint(m_hWnd, &paint);
for(int i=; i<(int)m_scrollinfo.nPage && i+m_scrollinfo.nPos<MAX_LINE; i++)
{
if( i+m_scrollinfo.nPos >= m_line )
::TextOut(hdc, , i*m_textMetric.tmHeight, TEXT(""), );
else
::TextOut(hdc, , i*m_textMetric.tmHeight, m_charArray[i+m_scrollinfo.nPos], wcslen(m_charArray[i+m_scrollinfo.nPos]));
}
::EndPaint(m_hWnd, &paint);
::ReleaseDC(m_hWnd, hdc);
return ;
}
} return ;
}
LPCTSTR KeyBoard::GetMyClassName()
{
return TEXT("keyBoardClass");
}

main

#include "KeyBoard.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nShowCmd )
{
KeyBoard key(hInstance); key.Create();
key.ShowWindow(nShowCmd); return key.exec();
}

最新文章

  1. 如何给现有的PDF文件添加页码
  2. Python连接MySQL
  3. python升级
  4. Linux SSH,FTP服务配置
  5. Enterprise app deployment on iOS 7.1 by github
  6. 【Cocos2d-Js基础教学(3)各种基类的定义和使用】
  7. benchmark
  8. JavaScript split() 方法
  9. 原生的AJAX写法,可以直接复制过来套用
  10. Windows API 常量定义
  11. Linux下搭建Oracle11g RAC(3)----创建用户及配置相关文件
  12. Main方法的执行过程(转)
  13. 模板引擎Jade详解
  14. [转]POJ1006: 中国剩余定理的完美演绎
  15. Linux系统下virtuoso数据库安装与使用
  16. Unity设置播放模式下始终先执行指定的场景
  17. 参数化查询 &#39;(@ActualShipTime datetime&#39; 需要参数 @AuthorizationNumber,但未提供该参数。
  18. MAVEN最佳实践:模块划分
  19. 预估高并发下API服务器数量
  20. Percona XtraDB Cluster 5.7

热门文章

  1. 为你下一个项目准备的 50 个 Bootstrap 插件
  2. Design Tutorial: Inverse the Problem
  3. SQL中Case的使用方法(上篇)(转)
  4. [dp]Codeforces30C Shooting Gallery
  5. 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 80070005 拒绝访问
  6. Easyui Datagrid rownumbers行号四位、五位显示不完全的解决办法
  7. cocos-html5 JS 写法基础 语言核心
  8. 驱动开发 - WDK 调试及 SVN 环境搭建
  9. TCP 协议如何保证可靠传输
  10. string.Split函数