由於個人需要,想找一個鍵盤記錄的程式,從網上下載了很多,多數都是需要註冊的,另外也多被殺軟查殺。於是決定自己寫一個,如果作為一個windows應用程式,可以實現抓取鍵盤的記錄。想要實現隨系統啟動的話,其中一種方法就是要作為windows服務,把代碼直接寫到服務裡邊並不能抓取到鍵盤的記錄,從網上翻閱資料及查看msdn才知道:
Windows 服務應用程式在不同於登入使用者的互動地區的視窗地區中運行。視窗地區是包含剪貼簿、一組全域原子和一組案頭對象的安全性實體。由於 Windows 服務的地區不是互動地區,因此 Windows 服務應用程式中引發的對話方塊將是不可見的,並且可能導致程式停止回應。同樣,錯誤資訊應記錄在 Windows 事件記錄中,而不是在使用者介面中引發。
服務程式一般使用的是LocalSystem帳戶,擁有自己的window station,和Default案頭,這個window station是不能於使用者互動的,也就是說,你不能在上面顯示視窗,它也不接受使用者的滑鼠、鍵盤等輸入。
我們使用使用者帳戶登入以後,看到的案頭,是WinSta0(window station)下的Default(desktop).
WinSta0下有3個案頭:
WinLogon :以Logon對話方塊的形式出現.當使用者登入以後,WinLogon.exe切換到Default desktop.
Default :這是Explorer.exe和所有使用者程式視窗出現的地方,也就是我們通常使用windows看見的地方.應用程式就運行在這個案頭上
Screen saver :系統閒置時候,運行屏保的案頭.
當你在“電腦管理”中選擇一個服務,修改屬性,選擇“登入”標籤頁的“允許服務與案頭互動”,那麼該服務就使用的是WinSta0(window station)下的Default(desktop). 你也就可以與你的服務進行互動操作了。這時,你能擷取default的案頭位元影像,因為線程的案頭就是WinSta0下的Default。要想同時獲得Winlogon案頭位元影像,應該先把線程的案頭設定成Winlogon。
此部分代碼公布如下:
//Service1.Designer.cs檔案
using System.Threading;
namespace KeyBoard
{
partial class Service1
{
/// <summary>
/// 必需的設計器變數。
/// </summary>
private System.ComponentModel.IContainer components = null;
Thread threadForm = null;
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
/// <param name="disposing">如果應釋放託管資源,為 true;否則為 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region 組件設計器產生的程式碼
/// <summary>
/// 設計器支援所需的方法 - 不要
/// 使用代碼編輯器修改此方法的內容。
/// </summary>
private void InitializeComponent()
{
//
// Service1
//
this.ServiceName = "Service1";
}
#endregion
}
}
//Service1.cs檔案
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
namespace KeyBoard
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
threadForm = new Thread(new ThreadStart(FormShow));
threadForm.Start();
}
protected override void OnStop()
{
if (threadForm != null)
{
if (threadForm.IsAlive)
{
threadForm.Abort();
threadForm = null;
}
}
}
void FormShow()
{
GetDesktopWindow();
IntPtr hwinstaSave = GetProcessWindowStation();
IntPtr dwThreadId = GetCurrentThreadId();
IntPtr hdeskSave = GetThreadDesktop(dwThreadId);
IntPtr hwinstaUser = OpenWindowStation("WinSta0", false,33554432);
if (hwinstaUser == IntPtr.Zero)
{
RpcRevertToSelf();
return ;
}
SetProcessWindowStation(hwinstaUser);
IntPtr hdeskUser = OpenDesktop("Default", 0, false, 33554432);
RpcRevertToSelf();
if (hdeskUser == IntPtr.Zero)
{
SetProcessWindowStation(hwinstaSave);
CloseWindowStation(hwinstaUser);
return ;
}
SetThreadDesktop(hdeskUser);
IntPtr dwGuiThreadId = dwThreadId;
MouseKeyBoard f=new MouseKeyBoard(); //此FORM1可以帶notifyIcon,可以顯示在托盤裡,使用者可點擊托盤表徵圖進行設定
System.Windows.Forms.Application.Run(f);
dwGuiThreadId = IntPtr.Zero;
SetThreadDesktop(hdeskSave);
SetProcessWindowStation(hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
}
[DllImport("user32.dll")]
static extern int GetDesktopWindow();
[DllImport("user32.dll")]
static extern IntPtr GetProcessWindowStation();
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThreadId();
[DllImport("user32.dll")]
static extern IntPtr GetThreadDesktop(IntPtr dwThread);
[DllImport("user32.dll")]
static extern IntPtr OpenWindowStation(string a,bool b,int c);
[DllImport("user32.dll")]
static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags,
bool fInherit, uint dwDesiredAccess);
[DllImport("user32.dll")]
static extern IntPtr CloseDesktop(IntPtr p);
[DllImport("rpcrt4.dll", SetLastError=true)]
static extern IntPtr RpcImpersonateClient(int i);
[DllImport("rpcrt4.dll", SetLastError=true)]
static extern IntPtr RpcRevertToSelf();
[DllImport("user32.dll")]
static extern IntPtr SetThreadDesktop(IntPtr a);
[DllImport("user32.dll")]
static extern IntPtr SetProcessWindowStation(IntPtr a);
[DllImport("user32.dll")]
static extern IntPtr CloseWindowStation(IntPtr a);
}
}