C# 螢幕操作錄製與回放
利用系統中的兩個特殊鉤子WH_JOURNALRECORD和WH_JOURNALPLAYBACK可以實現對螢幕上的所有操作進行錄製並以相同的操作流程回放剛才的螢幕操作,本程式是基於以下論文《Windows Hooks中錄製與回放鉤子的執行機制剖析》並用C#實現的。本程式已通過除錯。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace HookTEST
{
public partial class Form1 : Form
{
public delegate int HookProc(int nCode, IntPtr wParam,IntPtr lParam);//鉤子的宣告格式
//宣告鉤子子程delegate
HookProc RecordProc = null, PlayBackProc = null;
private int hHook = 0; //鉤子子程的指標
public bool bFlag = true; //在PlayBackProcedure()中,指示回放是否是在HC_SKIP後第一次進行HC_GETNEXT分支(要先了解回放的執行機制)
public int pos = 0; //在PlayBackProcedure()中指示當前要回放的訊息在msgList中的位置
// msgList陣列用於儲存錄制鉤子捕獲的訊息以便於回放鉤子對這些訊息進行回放
ArrayList msgList = new ArrayList();
#region 根據Win32定義本程式中所用到的常量
//定義nCode在本程式中用到的值
public const int HC_ACTION=0;
public const int HC_SKIP=2;
public const int HC_GETNEXT = 1;
//定義鉤子型別
public const int WH_JOURNALRECORD = 0;
public const int WH_JOURNALPLAYBACK = 1;
#endregion
#region (下面三個函式是錄製回放操作的核心函式)
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
#endregion
public Form1()
{
InitializeComponent();
}
#region 錄製子程
public int RecordProcedure(int nCode, IntPtr wParam, IntPtr lParam)
{
switch (nCode)
{
case HC_ACTION: //有滑鼠或鍵盤動作
EVENTMSG curMSG = null;
try
{
curMSG = (EVENTMSG)Marshal.PtrToStructure(lParam, typeof(EVENTMSG));
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
}
msgList.Add(curMSG);
break;
default:
break;
}
//return 1;
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
#endregion
#region 回放子程
public int PlayBackProcedure(int nCode, IntPtr wParam, IntPtr lParam)
{
int preTime = 0, nowTime = 0;
switch (nCode)
{
case HC_SKIP:
bFlag = true;
pos++;
return 0;
//break;
case HC_GETNEXT:
#region 判斷是否回放完畢
if (pos >= (msgList.Count - 2))
{
bool ret = UnhookWindowsHookEx(hHook);
if (ret == true)
{
MessageBox.Show("回放完畢!");
}
pos = 0;
hHook = 0;
return 0;
}
#endregion
#region 複製msgList中的當前訊息到lParam所指向的EVENTMSG中
EVENTMSG currentMSG = (EVENTMSG)msgList[pos];
try
{
Marshal.StructureToPtr(currentMSG, lParam, true);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
#endregion
#region 計算系統回放該訊息前要等待的時間
if ((pos > 0) && (bFlag == true))
{
bFlag = false;
EVENTMSG preMSG = (EVENTMSG)msgList[pos - 1];
preTime = preMSG.time;
nowTime = currentMSG.time;
return nowTime - preTime;
}
else
{
return 0;
}
#endregion
//break;
default:
break;
}
//return 0;
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
#endregion
/// <summary>
/// 開始錄製
/// </summary>
private void button1_Click(object sender, EventArgs e)
{
if(hHook==0) //錄製鉤子還未安裝,此時若按下按鈕則表示開始錄製,即進行鉤子安裝
{
RecordProc = new HookProc(this.RecordProcedure);
Process currentProcess = Process.GetCurrentProcess();
//安裝鉤子
hHook = SetWindowsHookEx(WH_JOURNALRECORD, RecordProc,currentProcess.MainModule.BaseAddress , 0);
if(hHook==0)
{
MessageBox.Show("SetWindowsHookEx Failed!");
return;
}
//清空msgList
msgList.Clear();
button1.Text = "停止錄製";
button3.Enabled = false;
this.WindowState = FormWindowState.Minimized;
this.Hide();
//this.notifyIcon1.Visible = true;
}
else //已安裝了鉤子。此時若按下按鈕則表示停止錄製,即制裁鉤子
{
bool ret = UnhookWindowsHookEx(hHook);
if(ret==false)
{
MessageBox.Show("UnhookWindowsHookEx Failed!");
return;
}
hHook = 0;
RecordProc=null;
button1.Text = "開始錄製";
button3.Enabled = true;
}
}
/// <summary>
/// 開始回放
/// </summary>
private void button3_Click(object sender, EventArgs e)
{
if (msgList.Count > 0)
{
this.WindowState = FormWindowState.Minimized;
this.Hide();
if (hHook == 0)
pos = 0;
PlayBackProc = new HookProc(this.PlayBackProcedure);
Process currentProcess = Process.GetCurrentProcess();
hHook = SetWindowsHookEx(WH_JOURNALPLAYBACK, PlayBackProc, currentProcess.MainModule.BaseAddress, 0);
if (hHook == 0)
{
MessageBox.Show("SetWindowsHookEx Failed!");
return;
}
//button1.Enabled=false;
}
else
{
MessageBox.Show("No recorded MSG Now,please record first!");
}
//解除安裝回放鉤子將在子程中進行
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.Visible = true;
this.WindowState = FormWindowState.Normal;
//this.notifyIcon1.Visible = false;
}
}
/// <summary>
/// 自定義訊息型別(除錯了半天 原來是訊息結構定義錯了 原先我定義的訊息結構是MSG,現在才知道MS為JOURNALPLAYBACK鉤子定義了特定的訊息結構)
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class EVENTMSG
{
public UInt32 message;
public UInt32 paramL;
public UInt32 paramH;
public Int32 time;
public UIntPtr hwnd;
}
}
相關文章
- 通過Linux命令實現螢幕錄製和回放Linux
- iOS ReplayKit 與 螢幕錄製iOS
- WebRTC本地分享螢幕,錄製螢幕Web
- 螢幕錄製軟體是怎麼錄製電腦螢幕影片的?
- iOS 螢幕錄製實現iOS
- .NET 視窗/螢幕錄製
- win10錄製螢幕快捷鍵 win10螢幕錄製在哪裡開啟Win10
- 使用瀏覽器錄製螢幕瀏覽器
- Any RecScreen for Mac螢幕錄製工具Mac
- 如何在 Mac 上錄製螢幕Mac
- IOS11螢幕錄製功能使用教程 IOS11螢幕錄製怎麼用?iOS
- vivo X6螢幕錄製怎麼用 vivo X6螢幕錄製使用教程
- 如何錄製螢幕影片?詳細的錄屏操作步驟告訴你
- Mac螢幕錄製工具Tipard Screen CaptureMacAPT
- 螢幕音訊錄製Aiseesoft Screen Recorder音訊AI
- Snagit 2022,螢幕錄製Git
- Easy Screen Recorder Mac(螢幕錄製工具)Mac
- Android 5.0 螢幕錄製/截圖Android
- Mac螢幕錄製工具——AV Recorder Screen CaptureMacAPT
- ScreenFlow for Mac(螢幕錄製和編輯)Mac
- Android 5.0+ 螢幕錄製實現Android
- UI 自動化錄製與回放系統UI
- win10的螢幕錄影功能在哪 win10怎麼錄製電腦螢幕Win10
- win10自帶錄製怎麼錄製桌面 windows10如何錄製螢幕Win10Windows
- Android Lollipop (5.0) 螢幕錄製實現Android
- 如何使用系統音訊錄製Mac螢幕?音訊Mac
- 10 款免費的 Mac 螢幕錄製工具Mac
- 流量錄製與回放在vivo的落地實踐
- 流量錄製回放工具jvm-sandbox-repeater入門篇——錄製和回放JVM
- screenium for mac下載-screenium for mac(螢幕錄製軟體)Mac
- ScreenFlow for mac(Mac好用的螢幕錄製軟體)Mac
- Mac FoneLab Screen Recorder Mac螢幕錄製軟體Mac
- Tipard Screen Capture for Mac(電腦螢幕錄製軟體)APTMac
- mac螢幕錄製Camtasia 2022漢化版Mac
- Android手機如何錄製螢幕及轉GIFAndroid
- win10的螢幕錄製在哪裡_win10錄屏怎麼錄製桌面Win10
- 掌握Snagit 2023:輕鬆實現螢幕錄製與截圖Git
- win10系統遊戲螢幕錄製如何關閉Win10遊戲