当前位置:   article > 正文

C#实现带光标的截图

C#实现带光标的截图

1,目的:

  • 可通过热键实现带光标与不带光标两种模式的截图。

2,知识点:

  • 快捷键的注册与注销。
  1. [DllImport("user32.dll", SetLastError = true)]
  2. public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);
  3. [DllImport("user32.dll", SetLastError = true)]
  4. public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
  • 光标信息的获取,光标图标的复制。
  1. [DllImport("user32.dll")]
  2. public static extern IntPtr CopyIcon(IntPtr hIcon);
  3. [DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
  4. public static extern bool GetCursorInfo(ref CURSORINFO cInfo);
  5. [DllImport("user32.dll", EntryPoint = "GetIconInfo")]
  6. public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO iInfo);
  • 对配置文件(ini文件)的读写。
  1. [DllImport("kernel32")]
  2. public static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
  3. [DllImport("kernel32")]
  4. public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retval, int size, string filePath);
  1. protected override void WndProc(ref Message m)
  2. {
  3. //WM_HOTKEY=0x0312,热键关联的消息ID
  4. const int WM_HOTKEY = 0x0312;
  5. //按快捷键
  6. switch (m.Msg)
  7. {
  8. case WM_HOTKEY:
  9. switch (m.WParam.ToInt32())
  10. {
  11. case 81: //按下的是Shift+F
  12. string ss = "";
  13. CaptureImage(ref ss);
  14. break;
  15. }
  16. break;
  17. }
  18. base.WndProc(ref m);
  19. }

3,效果展示:

  • 带图标效果:

  • 无图标效果

4代码:

  1. public partial class Form1 : Form
  2. {
  3. public Form1()
  4. {
  5. InitializeComponent();
  6. }
  7. bool isCaptureIcon = false;
  8. string savePath;
  9. private void Form1_Load(object sender, EventArgs e)
  10. {
  11. //判断是否存在配置文件如果不存在则创建,如果存在则读取
  12. string configPath = Path.GetFullPath("../../config.ini");
  13. if (File.Exists(configPath))
  14. {
  15. savePath = ReadFromINI(configPath, "Configuration", "Location");
  16. string str = ReadFromINI(configPath, "Configuration", "CaptureIcon");
  17. bool result;
  18. if (bool.TryParse(str, out result))
  19. {
  20. isCaptureIcon = result;
  21. }
  22. else
  23. {
  24. isCaptureIcon = false;
  25. }
  26. }
  27. else
  28. {
  29. File.Create(configPath);
  30. isCaptureIcon = false;
  31. }
  32. if (string.IsNullOrEmpty(savePath))
  33. {
  34. //获取当前启动位置的盘
  35. string startLocation = Application.StartupPath;
  36. string defaultLocation = Directory.GetDirectoryRoot(startLocation);
  37. savePath = defaultLocation;
  38. }
  39. textBox1.Text = savePath;
  40. checkBox1.Checked = isCaptureIcon;
  41. //进行热键注册
  42. APIHelper.RegisterHotKey(this.Handle, 81, KeyModifiers.Shift, Keys.C);
  43. }
  44. //设置截图存储路径
  45. private void btnOpenF_Click(object sender, EventArgs e)
  46. {
  47. using (FolderBrowserDialog fbd = new FolderBrowserDialog())
  48. {
  49. if (fbd.ShowDialog() == DialogResult.OK)
  50. {
  51. savePath = textBox1.Text = fbd.SelectedPath;
  52. }
  53. }
  54. }
  55. //保存配置
  56. private void btnSave_Click(object sender, EventArgs e)
  57. {
  58. string iniPath = Path.GetFullPath("../../config.ini");
  59. if (!File.Exists(iniPath))
  60. {
  61. File.Create(iniPath);
  62. }
  63. WriteToINI(iniPath, "Configuration", "Location", textBox1.Text);
  64. WriteToINI(iniPath, "Configuration", "CaptureIcon", isCaptureIcon.ToString());
  65. MessageBox.Show("已保存", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
  66. }
  67. private void checkBox1_CheckedChanged(object sender, EventArgs e)
  68. {
  69. isCaptureIcon = checkBox1.Checked;
  70. }
  71. private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  72. {
  73. //热键注销
  74. APIHelper.UnregisterHotKey(this.Handle, 81);
  75. }
  76. //隐藏窗口
  77. private void btnHide_Click(object sender, EventArgs e)
  78. {
  79. this.Hide();
  80. }
  81. private void btnCapture_Click(object sender, EventArgs e)
  82. {
  83. string filePath = "";
  84. if (CaptureImage(ref filePath))
  85. {
  86. MessageBox.Show("已截图:" + filePath);
  87. }
  88. else
  89. {
  90. MessageBox.Show("截图失败");
  91. }
  92. }
  93. //双击图标显示窗口
  94. private void notifyIcon1_DoubleClick(object sender, EventArgs e)
  95. {
  96. this.Show();
  97. this.WindowState = FormWindowState.Normal;
  98. this.Activate();
  99. }
  100. private void toolStripExit_Click(object sender, EventArgs e)
  101. {
  102. APIHelper.UnregisterHotKey(this.Handle, 81);
  103. Application.Exit();
  104. }
  105. private void toolStripShow_Click(object sender, EventArgs e)
  106. {
  107. this.Visible = true;
  108. }
  109. //对接收的消息进行重写
  110. protected override void WndProc(ref Message m)
  111. {
  112. //WM_HOTKEY=0x0312,热键关联的消息ID
  113. const int WM_HOTKEY = 0x0312;
  114. //按快捷键
  115. switch (m.Msg)
  116. {
  117. case WM_HOTKEY:
  118. switch (m.WParam.ToInt32())
  119. {
  120. case 81: //按下的是Shift+F
  121. string ss = "";
  122. CaptureImage(ref ss);
  123. break;
  124. }
  125. break;
  126. }
  127. base.WndProc(ref m);
  128. }
  129. bool CaptureImage(ref string filePath)
  130. {
  131. Bitmap img;
  132. if (!isCaptureIcon)
  133. {
  134. img = CaptureNoCursor();
  135. string imgDir = Path.Combine(savePath, "Image", "NoCursor");
  136. if (!Directory.Exists(imgDir))
  137. {
  138. Directory.CreateDirectory(imgDir);
  139. }
  140. string fileName = "IMG_" + DateTime.Now.ToString("HHmmss") + ".png";
  141. filePath = Path.Combine(imgDir, fileName);
  142. }
  143. else
  144. {
  145. img = CaptureCursor();
  146. string imgDir = Path.Combine(savePath, "Image", "Cursor");
  147. if (!Directory.Exists(imgDir))
  148. {
  149. Directory.CreateDirectory(imgDir);
  150. }
  151. string fileName = "IMG_" + DateTime.Now.ToString("HHmmss") + ".png";
  152. filePath = Path.Combine(imgDir, fileName);
  153. }
  154. if (img != null)
  155. {
  156. img.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
  157. return true;
  158. }
  159. else
  160. {
  161. return false;
  162. }
  163. }
  164. /// <summary>
  165. /// 不含光标的截图
  166. /// </summary>
  167. /// <returns></returns>
  168. Bitmap CaptureNoCursor()
  169. {
  170. //获取屏幕尺寸
  171. int width = APIHelper.GetSystemMetrics(0);
  172. int height = APIHelper.GetSystemMetrics(1);
  173. //创建图片
  174. Bitmap img = new Bitmap(width, height);
  175. using (Graphics g = Graphics.FromImage(img))
  176. {
  177. g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  178. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  179. g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(width, height));
  180. }
  181. return img;
  182. }
  183. /// <summary>
  184. /// 包含光标的截图
  185. /// </summary>
  186. /// <returns></returns>
  187. Bitmap CaptureCursor()
  188. {
  189. //获取光标信息
  190. CURSORINFO cursor = new CURSORINFO();
  191. cursor.cbSize = Marshal.SizeOf(cursor);
  192. if (APIHelper.GetCursorInfo(ref cursor))
  193. {
  194. //flags==1时光标处于显示中
  195. if (cursor.flags == 1)
  196. {
  197. ICONINFO iconinfo;
  198. //复制光标
  199. IntPtr hwn = APIHelper.CopyIcon(cursor.hCursor);
  200. //获取光标信息
  201. if (APIHelper.GetIconInfo(hwn, out iconinfo))
  202. {
  203. Icon icon = Icon.FromHandle(hwn);
  204. Point iconScreenPoint = new Point(cursor.ptScreenPos.X - iconinfo.xHotspot, cursor.ptScreenPos.Y - iconinfo.yHotspot);
  205. //获取屏幕尺寸
  206. int width = Screen.PrimaryScreen.Bounds.Width;
  207. int height = Screen.PrimaryScreen.Bounds.Height;
  208. //创建图片
  209. Bitmap img = new Bitmap(width, height);
  210. using (Graphics g = Graphics.FromImage(img))
  211. {
  212. g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  213. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  214. g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(width, height));
  215. g.DrawIcon(icon, iconScreenPoint.X, iconScreenPoint.Y);
  216. }
  217. return img;
  218. }
  219. }
  220. }
  221. return null;
  222. }
  223. public static string ReadFromINI(string filePath, string rootValue, string key, string defValue = "")
  224. {
  225. StringBuilder sb = new StringBuilder(1024);
  226. APIHelper.GetPrivateProfileString(rootValue, key, defValue, sb, 1024, filePath);
  227. return sb.ToString();
  228. }
  229. public static void WriteToINI(string filePath, string rootValue, string key, string newVal)
  230. {
  231. APIHelper.WritePrivateProfileString(rootValue, key, newVal, filePath);
  232. }
  233. }
  234. /// <summary>
  235. /// 有关图标或光标的信息
  236. /// </summary>
  237. [StructLayout(LayoutKind.Sequential)]
  238. struct ICONINFO
  239. {
  240. /// <summary>
  241. /// 指定此结构是定义图标还是游标。 值为 TRUE 指定图标; FALSE 指定游标。
  242. /// </summary>
  243. public bool fIcon;
  244. /// <summary>
  245. /// 光标热点的 x 坐标。 如果此结构定义了图标,则热点始终位于图标的中心,并且忽略此成员。
  246. /// </summary>
  247. public Int32 xHotspot;
  248. /// <summary>
  249. /// 光标热点的 y 坐标。 如果此结构定义了图标,则热点始终位于图标的中心,并且忽略此成员。
  250. /// </summary>
  251. public Int32 yHotspot;
  252. /// <summary>
  253. /// 单色掩码 位图图标的句柄。
  254. /// </summary>
  255. public IntPtr hbmMask;
  256. /// <summary>
  257. /// 图标颜色 位图的句柄。
  258. /// </summary>
  259. public IntPtr hbmColor;
  260. }
  261. /// <summary>
  262. /// 全局游标信息
  263. /// </summary>
  264. [StructLayout(LayoutKind.Sequential)]
  265. struct CURSORINFO
  266. {
  267. /// <summary>
  268. /// 结构大小(以字节为单位)。 调用方必须将此设置为 sizeof(CURSORINFO)。
  269. /// </summary>
  270. public Int32 cbSize;
  271. /// <summary>
  272. /// 游标状态。 此参数的取值可为下列值之一:0:光标处于隐藏。1:光标处于显示。2:Windows 8:取消光标。 此标志指示系统未绘制光标,因为用户是通过触摸或笔而不是鼠标提供输入。
  273. /// </summary>
  274. public Int32 flags;
  275. /// <summary>
  276. /// 光标的句柄。
  277. /// </summary>
  278. public IntPtr hCursor;
  279. /// <summary>
  280. /// 接收光标的屏幕坐标的结构。
  281. /// </summary>
  282. public Point ptScreenPos;
  283. }
  284. [Flags()]
  285. public enum KeyModifiers
  286. {
  287. None = 0,
  288. Alt = 1,
  289. Ctrl = 2,
  290. Shift = 4,
  291. WindowsKey = 8
  292. }
  293. class APIHelper
  294. {
  295. /// <summary>
  296. /// 获取与windows环境有关的信息
  297. /// </summary>
  298. /// <param name="mVal">指定获取信息</param>
  299. /// <returns></returns>
  300. [DllImport("user32.dll")]
  301. public static extern int GetSystemMetrics(int mVal);
  302. /// <summary>
  303. /// 获取指定图标或者鼠标的一个副本
  304. /// </summary>
  305. /// <param name="hIcon">欲复制的图标或指针的句柄</param>
  306. /// <returns></returns>
  307. [DllImport("user32.dll")]
  308. public static extern IntPtr CopyIcon(IntPtr hIcon);
  309. [DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
  310. public static extern bool GetCursorInfo(ref CURSORINFO cInfo);
  311. [DllImport("user32.dll", EntryPoint = "GetIconInfo")]
  312. public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO iInfo);
  313. [DllImport("kernel32")]
  314. public static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
  315. [DllImport("kernel32")]
  316. public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retval, int size, string filePath);
  317. /// <summary>
  318. /// 热键注册
  319. /// </summary>
  320. /// <param name="hWnd">要定义热键的窗口的句柄 </param>
  321. /// <param name="id">定义热键ID(不能与其它ID重复) </param>
  322. /// <param name="fsModifiers">标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效 </param>
  323. /// <param name="vk">定义热键的内容 </param>
  324. /// <returns>如果函数执行成功,返回值不为0。如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。</returns>
  325. [DllImport("user32.dll", SetLastError = true)]
  326. public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk);
  327. /// <summary>
  328. /// 热键注销
  329. /// </summary>
  330. /// <param name="hWnd">要取消热键的窗口的句柄 </param>
  331. /// <param name="id">要取消热键的ID </param>
  332. /// <returns></returns>
  333. [DllImport("user32.dll", SetLastError = true)]
  334. public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
  335. /// <summary>
  336. /// 从INI文件中读取数据
  337. /// </summary>
  338. /// <param name="filePath">INI文件的全路径</param>
  339. /// <param name="rootValue">根节点值,例如根节点[ConnectString]的值为:ConnectString</param>
  340. /// <param name="key">根节点下的键</param>
  341. /// <param name="defValue">当标记值未设定或不存在时的默认值</param>
  342. /// <returns></returns>
  343. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/45167
推荐阅读
相关标签
  

闽ICP备14008679号