ScreenCap:C# 屏幕捕获应用程序(基于 GuyThiebaut 的 TeboScreen 分支)






4.87/5 (24投票s)
一个基于 GuyThiebaut 的 TeboScreen 的 C# 屏幕捕获应用程序。
引言
此应用程序在后台运行,并接管“Print Screen”按钮,允许以两种不同的方式捕获屏幕。
- 捕获屏幕:这就像字面意思一样;它基本上捕获整个屏幕。
- 捕获区域:按住鼠标左键,用户可以绘制一个矩形,指定他们希望捕获的屏幕部分。然后,用户可以选择三种方法之一来发送绘制矩形后面的区域(
剪贴板
,打印机
,电子邮件
)。绘制完成后,可以在将图像发送到所需目的地之前调整矩形的大小和移动。
背景
我的雇主最近从一个旧的 Telnet 应用程序迁移到一个 Windows 应用程序。旧应用程序允许用户点击“Print Screen”按钮并将其会话屏幕发送到打印机。我们的许多用户没有 Windows 使用经验,他们需要能够轻松地捕获屏幕并将其发送到打印机,而无需费力地绕过 Windows 环境。
在互联网上搜索好的屏幕截图程序来实现这一点后,我们发现的大部分内容都比较弱而且昂贵。我知道这个项目对我来说应该不会很难编写;所以,我开始寻找一些开源来帮助我快速完成任务,并发现了 Code Project 上的 GuyThiebaut 的“TeboScreen
”应用程序:TeboScreen
Using the Code
我重点关注了几个方面来增强原始的 TeboScreen
- 在后台运行,并在按下“Print Screen”按钮时激活
- 支持双显示器,无论显示器之间是否存在尺寸差异
- 自动将屏幕截图发送到三个设备:
剪贴板
、打印机
和电子邮件
- 方便最终用户使用
考虑到这一点,我不会详细介绍原始项目中涵盖的冗余细节。
在后台运行
我们所需要做的就是为主窗体的 Shown
事件添加一个处理程序
private void ControlPanel_Shown(object sender, EventArgs e)
{
this.Hide();
}
处理 Print Screen 按钮
这需要编写一个程序集,根据这个讨论 KeyHook。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Reflection;
namespace KeyHook
{
public class KeyHooker
{
public static event EventHandler PrintScreenBtnEvent = null;
[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int extraInfo;
}
public delegate int HookProc(int nCode, int wParam, IntPtr ptrKBDLLHOOKSTRUCT);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx
(int idHook, HookProc callBack, IntPtr hMod, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, int wParam, IntPtr lParam);
private static IntPtr kbh_Handle;
private static HookProc kbh_HookProc;
private const int VK_SNAPSHOT = 0x2C;
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
private const int WH_KEYBOARD_LL = 13;
private static int LowLevelKeyboardProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode < 0)
{
CallNextHookEx(kbh_Handle, nCode, wParam, lParam);
return 0;
}
if (wParam == WM_KEYDOWN)
{
IntPtr kbdll = lParam;
KBDLLHOOKSTRUCT kbdllstruct =
(KBDLLHOOKSTRUCT)Marshal.PtrToStructure(kbdll, typeof(KBDLLHOOKSTRUCT));
if (kbdllstruct.vkCode == VK_SNAPSHOT)
{
if (PrintScreenBtnEvent != null)
PrintScreenBtnEvent(null, new EventArgs());
return -1;
}
}
return CallNextHookEx(kbh_Handle, nCode, wParam, lParam);
}
public static void HookKeyboard()
{
try
{
kbh_HookProc = LowLevelKeyboardProc;
kbh_Handle = SetWindowsHookEx(WH_KEYBOARD_LL, kbh_HookProc,
Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
if (kbh_Handle == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(String.Format("ERROR: {0}", ex.Message));
}
}
}
}
为了实现这一点,我在 KeyHooker
类中添加了一个委托
public static event EventHandler PrintScreenBtnEvent = null;
双显示器支持
为此,我不得不查看 System.Windows.Forms.
Screen
类。下面是一段代码片段,用于存储主显示器的索引。主显示器是 TeboScreen
应用程序的基础,因此此项目中主显示器的任何代码都将相同。如果正在处理的显示器不是主显示器,我必须对代码进行调整。
private int GetPrimaryMonIdx()
{
Screen[] sc;
sc = Screen.AllScreens;
int idx = 0;
foreach (Screen s in sc)
{
if (s.Bounds.Left == System.Windows.Forms.Screen.PrimaryScreen.Bounds.Left)
break;
else
idx++;
}
return (idx <= sc.Length) ? idx : 0;
}
退出程序
当主屏幕(来自上面的屏幕截图)显示并具有焦点时,按 Ctrl-Alt-S 然后按 X。