通過C#編寫一個簡易的Windows截屏增強工具
半年前我開源了 DreamScene2 一個小而快并且功能強大的 Windows 動態(tài)桌面軟件。有很多的人喜歡,這使我有了繼續(xù)做開源的信心。這是我的第二個開源作品 ScreenshotEx 一個簡單易用的 Windows 截屏增強工具。
前言
在使用 Windows 系統(tǒng)的截屏快捷鍵 PrintScreen
截屏時,如果需要把截屏保存到文件,需要先粘貼到畫圖工具然后另存為文件。以前我還沒有覺得很麻煩,后來使用了 macOS 系統(tǒng)的截屏工具,我才知道原來一個小小的截屏工具也可以這么簡單易用。于是參考 macOS 系統(tǒng)的截屏工具做了一個 Windows 版的。
功能
自動保存截屏到桌面
點擊截屏預覽可以編輯截屏
實現(xiàn)原理
如果想在按下系統(tǒng)的截屏快捷鍵后做一些事情,能想到的方法應該就是如何監(jiān)聽鍵盤事件。WIN32 API 提供的 SetWindowsHookExA 鉤子函數(shù)剛好可以實現(xiàn)這個需求,idHook
參數(shù)設置成 WH_KEYBOARD_LL
時是低等級鍵盤鉤子可以捕獲鍵盤消息。
SetWindowsHookExA
函數(shù)定義
HHOOK SetWindowsHookExA( [in] int idHook, // 鉤子類型 [in] HOOKPROC lpfn, // 鉤子處理函數(shù) [in] HINSTANCE hmod, // 模塊句柄 [in] DWORD dwThreadId // 線程Id );
鍵盤處理函數(shù)定義
LRESULT CALLBACK LowLevelKeyboardProc( _In_?int ???nCode, _In_?WPARAM wParam, // 鍵盤消息 _In_?LPARAM lParam // KBDLLHOOKSTRUCT 結(jié)構(gòu)體指針 );
代碼
C#PInvoke定義
const int HC_ACTION = 0; const int WH_KEYBOARD_LL = 13; const int WM_KEYUP = 0x0101; const int WM_SYSKEYUP = 0x0105; const int VK_SNAPSHOT = 0x2C; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct KBDLLHOOKSTRUCT { public uint vkCode; public uint scanCode; public uint flags; public uint time; public UIntPtr dwExtraInfo; } [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr HookProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam); [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hmod, int dwThreadId); [DllImport("User32.dll", SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("User32.dll", SetLastError = false, ExactSpelling = true)] public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam); [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr GetModuleHandle([Optional] string lpModuleName);
注冊鍵盤鉤子
需要注意:因為 SetWindowsHookEx
是非托管函數(shù)第二個參數(shù)是個委托類型,GC
不會記錄非托管函數(shù)對 .NET
對象的引用。如果用臨時變量保存委托出作用域就會被 GC
釋放,當 SetWindowsHookEx
去調(diào)用已經(jīng)被釋放的委托就會報錯。
SetWindowsHookEx
函數(shù)第一個參數(shù)傳 WH_KEYBOARD_LL
低等級鍵盤鉤子、第二個參數(shù)傳鍵盤消息處理函數(shù)的委托、第三個參數(shù)使用 GetModuleHandle
函數(shù)獲取模塊句柄、第四個參數(shù)傳 0。
HookProc _hookProc; IntPtr _hhook; void StartHook() { _hookProc = new HookProc(LowLevelKeyboardProc); // 使用成員變量保存委托 _hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, GetModuleHandle(null), 0); // 注冊鍵盤鉤子,保存返回值卸載鉤子時用到。GetModuleHandle(null) 獲取當前模塊句柄 }
鍵盤消息處理函數(shù)
在鍵盤消息處理函數(shù)里面捕獲 PrintScreen
按鍵消息,然后顯示預覽和保存圖片邏輯
IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam) { if (nCode == HC_ACTION) { if (lParam.vkCode == VK_SNAPSHOT) // 捕獲 PrintScreen 按鍵消息 { if ((int)wParam == WM_KEYUP || (int)wParam == WM_SYSKEYUP) // 按鍵釋放時保存圖片 SaveImage(); else _previewWindow.SetHide(); } } return CallNextHookEx(_hhook, nCode, wParam, ref lParam); }
保存圖片
從系統(tǒng)剪貼板獲取圖片
void SaveImage() { if (Clipboard.ContainsImage()) { if (!Directory.Exists(_settings.SavePath)) Directory.CreateDirectory(_settings.SavePath); string ext = "png"; ImageFormat imageFormat = ImageFormat.Png; switch (_settings.SaveExtension) { case 0: imageFormat = ImageFormat.Png; ext = "png"; break; case 1: imageFormat = ImageFormat.Jpeg; ext = "jpg"; break; case 2: imageFormat = ImageFormat.Bmp; ext = "bmp"; break; } if (_settings.SaveName == 0) { string name = DateTime.Now.ToString("yyyy-MM-dd HH.mm.ss"); _saveFilePath = Path.Combine(_settings.SavePath, $"{PrefixName} {name}.{ext}"); } else { do { _saveFilePath = Path.Combine(_settings.SavePath, $"{PrefixName} {_nameIndex}.{ext}"); _nameIndex++; } while (File.Exists(_saveFilePath)); } Image image = Clipboard.GetImage(); image.Save(_saveFilePath, imageFormat); if (_settings.IsPlaySound) _soundPlayer.Play(); if (_settings.IsShowPreview) _previewWindow.SetImage(_saveFilePath); } }
以上就是通過C#編寫一個簡易的Windows截屏增強工具的詳細內(nèi)容,更多關于C#截屏增強工具的資料請關注腳本之家其它相關文章!
相關文章
C# 實現(xiàn)把double 存成兩位精度小數(shù)
這篇文章主要介紹了C# 實現(xiàn)把double 存成兩位精度小數(shù),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12C#實現(xiàn)將數(shù)組內(nèi)元素打亂順序的方法
這篇文章主要介紹了C#實現(xiàn)將數(shù)組內(nèi)元素打亂順序的方法,涉及C#數(shù)組遍歷及隨機數(shù)操作的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08.NET中保證線程安全的高級方法Interlocked類使用介紹
這篇文章主要介紹了.NET中保證線程安全的高級方法Interlocked類使用介紹,Interlocked類可以為為多個線程共享的變量提供原子操作,需要的朋友可以參考下2014-07-07