win32键盘记录 -- 自定义窗口类
最近学了些关于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=0, int winRight=600, int winTop=0, int winBottom=800); ~WinClassBase(); virtual int HandleMessage(UINT message,WPARAM wParam,LPARAM lParam) = 0; virtual LPCTSTR GetMyClassName() = 0; //创建窗口 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+1); } 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=0; for(i=0; i<registeredClassArray.size(); ++i) { if( registeredClassArray[i] == std::wstring(this->GetMyClassName()) ) { break; } } //注册 if( i == registeredClassArray.size() ) { WNDCLASS win; win.cbClsExtra = 0; win.cbWndExtra = 0; 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(0 != ::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[128] = {0}; ::swprintf(errorMsg, 128, 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(0); break; default: if(pThis != NULL && pThis->HandleMessage(message, wParam, lParam) == 0) { return DefWindowProc(hwnd, message, wParam, lParam); } else if(pThis == NULL) { return DefWindowProc(hwnd, message, wParam, lParam); } break; } return 0; } 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 0; }
KeyBoard.h
#pragma once #include "WinClassBase.h" #define MAX_LINE 1000 class KeyBoard : public WinClassBase { public: KeyBoard(HINSTANCE hInastance, HWND HwndParent = NULL, int winLeft=0, int winRight=600, int winTop=0, int winBottom=800); ~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][100]; };
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 - 1; m_scrollinfo.nMin = 0; m_scrollinfo.nPos = 0; m_line = 0; return 1; } 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 1; } case WM_VSCROLL: { switch(LOWORD(wParam)) { case SB_BOTTOM: m_scrollinfo.nPos = m_line; break; case SB_LINEDOWN: m_scrollinfo.nPos = (m_scrollinfo.nPos+1); break; case SB_LINEUP: if( m_scrollinfo.nPos >= 0 ) m_scrollinfo.nPos = m_scrollinfo.nPos-1; 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 1; } case WM_CHAR: { if(m_line < MAX_LINE) { wmemset(m_charArray[m_line], 0, 100); swprintf(m_charArray[m_line], 100, 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, 0); else { RECT rect; rect.left = 0; rect.right = m_rect.right; rect.top = ((m_line-1) % m_scrollinfo.nPage) * m_textMetric.tmHeight; rect.bottom = rect.top + m_textMetric.tmHeight; InvalidateRect(m_hWnd, &rect, TRUE); } } return 1; } case WM_PAINT: { PAINTSTRUCT paint; HDC hdc = ::BeginPaint(m_hWnd, &paint); for(int i=0; i<(int)m_scrollinfo.nPage && i+m_scrollinfo.nPos<MAX_LINE; i++) { if( i+m_scrollinfo.nPos >= m_line ) ::TextOut(hdc, 0, i*m_textMetric.tmHeight, TEXT(""), 0); else ::TextOut(hdc, 0, 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 1; } } return 0; } 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(); }