首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 熱鍵驅動螢幕擷圖工具:全域鍵盤鉤子 DLL + 位圖儲存完整實作

     編輯:關於VC++

本工具結合 全域鍵盤鉤子 DLL (共享記憶體段) 與 GDI 螢幕截取,使用者自訂熱鍵 (如 Ctrl+F9) 即可在任何應用程式中將全螢幕內容存為 BMP 檔。完整原始碼包含 DLL 端鉤子管理、主程式熱鍵註冊、訊息回應、螢幕 DC 複製、BMP 檔案寫入。

一、熱鍵管理 DLL 設計

共享資料段 (跨進程同步)


#pragma data_seg("SHARED_DATA")
HHOOK   g_hHook = NULL;
UINT    g_nHookCount = 0;
UCHAR   g_HotKeyVK[MAX_HOTKEYS] = {0};
UCHAR   g_HotKeyMod[MAX_HOTKEYS] = {0}; // MOD_CONTROL=4, MOD_ALT=2, MOD_SHIFT=1
HWND    g_hTargetWnd[MAX_HOTKEYS] = {0};
int     g_nKeyCount = 0;
UCHAR   g_CurrentMod = 0; // 即時修飾鍵狀態
#pragma data_seg()
#pragma comment(linker, "/section:SHARED_DATA,RWS")
所有變數必須初始化,否則連結器會放入一般資料段導致共享失效。

匯出函式:註冊/移除熱鍵


BOOL __stdcall AddHotkey(HWND hWnd, UCHAR vk, UCHAR mod) {
  for (int i=0; i

鍵盤鉤子程序


LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
  if (nCode != HC_ACTION) return CallNextHookEx(g_hHook, nCode, wParam, lParam);

  BOOL bKeyUp = (lParam & 0xC0000000) == 0xC0000000; // bit 30-31 = 11 表示釋放
  if (bKeyUp) {
    switch (wParam) {
      case VK_CONTROL: g_CurrentMod &= ~4; break;
      case VK_MENU:    g_CurrentMod &= ~2; break;
      case VK_SHIFT:   g_CurrentMod &= ~1; break;
    }
  } else { // Key Down
    switch (wParam) {
      case VK_CONTROL: g_CurrentMod |= 4; break;
      case VK_MENU:    g_CurrentMod |= 2; break;
      case VK_SHIFT:   g_CurrentMod |= 1; break;
    }
  }

  // 比對已註冊熱鍵
  for (int i=0; i

二、主程式:對話方塊應用

動態載入 DLL 並註冊熱鍵


typedef BOOL (__stdcall *PFN_ADD)(HWND,UCHAR,UCHAR);
typedef BOOL (__stdcall *PFN_DEL)(HWND,UCHAR,UCHAR);
HMODULE hHookDll = LoadLibrary(_T("HotkeyHook.dll"));
PFN_ADD pAdd = (PFN_ADD)GetProcAddress(hHookDll, "AddHotkey");
PFN_DEL pDel = (PFN_DEL)GetProcAddress(hHookDll, "DeleteHotkey");

// UI 讓使用者選擇修飾鍵 (Checkbox) + 功能鍵 (ComboBox)
// 按下「設定」呼叫 pAdd(m_hWnd, vk, mod);

處理 WM_HOTKEY 觸發截圖


LRESULT CCapDlg::WindowProc(UINT msg, WPARAM wp, LPARAM lp) {
  if (msg == WM_HOTKEY && lp == WM_KEYDOWN) {
    SaveBmp();
    return 0;
  }
  return CDialog::WindowProc(msg, wp, lp);
}

螢幕截圖存 BMP 核心函式


void CCapDlg::SaveBmp() {
  CDC dc; dc.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
  int w = GetSystemMetrics(SM_CXSCREEN);
  int h = GetSystemMetrics(SM_CYSCREEN);

  CBitmap bmp; bmp.CreateCompatibleBitmap(&dc, w, h);
  CDC memDC; memDC.CreateCompatibleDC(&dc);
  CBitmap* pOld = memDC.SelectObject(&bmp);
  memDC.BitBlt(0,0,w,h, &dc,0,0, SRCCOPY);
  memDC.SelectObject(pOld);

  BITMAP bm; bmp.GetBitmap(&bm);
  DWORD dwSize = bm.bmWidthBytes * bm.bmHeight;
  LPSTR pBits = (LPSTR)GlobalAllocPtr(GPTR, dwSize);

  BITMAPINFOHEADER bih = {0};
  bih.biSize = sizeof(bih);
  bih.biWidth = bm.bmWidth;
  bih.biHeight = bm.bmHeight;
  bih.biPlanes = 1;
  bih.biBitCount = bm.bmBitsPixel;
  bih.biCompression = BI_RGB;
  bih.biSizeImage = dwSize;

  GetDIBits(dc.m_hDC, bmp, 0, h, pBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);

  // 寫入 BMP 檔案
  static int nCount = 0;
  CString path; path.Format(_T("%spict%04d.bmp"), m_strSavePath, nCount++);
  CFile file; file.Open(path, CFile::modeCreate|CFile::modeWrite);

  BITMAPFILEHEADER bfh = {0};
  bfh.bfType = 0x4D42; // 'BM'
  bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
  bfh.bfSize = bfh.bfOffBits + dwSize;

  file.WriteHuge(&bfh, sizeof(bfh));
  file.WriteHuge(&bih, sizeof(bih));
  file.WriteHuge(pBits, dwSize);
  file.Close();

  GlobalFreePtr(pBits);
  UpdateStatus(nCount);
}

三、部署與測試步驟

  1. 編譯 HotkeyHook.dll → 複製至 C:\Windows\System32 (或應用程式同目錄)。
  2. 編譯主程式 ScreenCap.exe。
  3. 執行主程式,設定儲存路徑、熱鍵 (如 Ctrl+F9),點擊「設定」。
  4. 切換至任意視窗,按下熱鍵,檢查儲存路徑是否產生 pict0000.bmp、pict0001.bmp...。

注意事項

  • 64 位元 OS 需編譯 64 位元 DLL,否則無法鉤住 64 位元進程。
  • Vista+ 建議改用 WH_KEYBOARD_LL (低階鉤子),無需 DLL、不受 Session 0 隔離影響。
  • 多螢幕環境 SM_CXSCREEN/CYSCREEN 僅回傳主螢幕尺寸,需改用 EnumDisplayMonitors 計算虛擬螢幕範圍。
  • BMP 未壓縮,檔案較大;生產環境建議加入 PNG/JPEG 壓縮 (GDI+/WIC)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved