C# 通過服務啟動表單(把表單添加到服務裡)實現使用者互動的windows服務[轉寄]

來源:互聯網
上載者:User

由於個人需要,想找一個鍵盤記錄的程式,從網上下載了很多,多數都是需要註冊的,另外也多被殺軟查殺。於是決定自己寫一個,如果作為一個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);
           
    }

}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.