由于个人需要,想找一个键盘记录的程序,从网上下载了很多,多数都是需要注册的,另外也多被杀软查杀。于是决定自己写一个,如果作为一个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);
           
    }

}

C# 通过服务启动窗体(把窗体添加到服务里)实现用户交互的windows服务[转发]的更多相关文章

  1. .NET实现可交互的WINDOWS服务(转载自CSDN"烈火蜓蜻")

    Windows 服务应用程序在不同于登录用户的交互区域的窗口区域中运行.窗口区域是包含剪贴板.一组全局原子和一组桌面对象的安全对象.由于 Windows 服务的区域不是交互区域,因此 Windows ...

  2. 服务启动错误1053,一例解决方案(给用户添加NetworkService权限)

    WIndows XP的服务中,有一个服务需要以NT  AUTHORITY/NetworkService用户启动,但怎么也启动不起来,使用本地系统帐户启动没有任何问题,但是换成NetworkServic ...

  3. win7 提升windows服务权限使非管理员用户可以控制windows服务的开启和关闭

    #include <windows.h>#include <tchar.h>#include <strsafe.h>#include <aclapi.h> ...

  4. c# 通过Windows服务启动外部程序

    1. 新建一个Windows服务应用程序 创建项目——>Visual C# 左侧的"+"——>Windows ——>Windows 服务(右侧模板)——>输 ...

  5. logstash服务启动脚本

    logstash服务启动脚本 最近在弄ELK,发现logstash没有sysv类型的服务启动脚本,于是按照网上一个老外提供的模板自己进行修改 #添加用户 useradd logstash -M -s ...

  6. 以Windows服务方式启动MySQL,并将其默认编码设置为UTF-8

    系统环境:Windows XP Professional 版本 2002 Service Pack 3 // 第1步:创建选项文件.首先下载mysql-5.5.12-win32.zip,只需复制mys ...

  7. Tomcat服务启动成功,但访问index.jsp出错 (jspInit)

    本文引用自 --> http://zhouhaitao.iteye.com/blog/1164736 Tomcat服务启动成功,但访问index.jsp出错 环境:Tomcat6 + jdk6 ...

  8. CreateProcessAsUser,C#写的windows服务弹框提示消息或者启动子进程

    服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...

  9. SpringBoot注册Windows服务和启动报错的原因

    SpringBoot注册Windows服务和启动报错的原因 Windows系统启动Java程序会弹出黑窗口.黑窗口有几点不好.首先它不美观:其次容易误点导致程序关闭:但最让我匪夷所思的是:将鼠标光标选 ...

随机推荐

  1. laravel之缓存配置文件

    清除之前配置文件缓存,并生成新的配置文件缓存, get bash: php artisan config:cache 如下图,以上命令会将config文件夹下所有的文件内容缓存到bootstrap/c ...

  2. NTDLL未文档化函数RtlGetNtVersionNumbers获取操作系统版本

    作为新手,对获取操作系统版本号好奇过,因为曾经假象过一个场景:自己的程序在windows xp环境下编译,在windows 2003, windows 7,windows 8是否需要提权或者兼容处理, ...

  3. MAC 安装j2ee.sh的办法

    It says it needs the DISPLAY variable set - what do I need to set it to? Instead of saying: ./java_e ...

  4. yarn container启动失败

    在yarn资源管理的集群上运行spark程序,无法读取的数据多与少,都会报这个错误,但是其他程序在集群上能够正常运行. 16/11/14 00:13:44 WARN cluster.YarnSched ...

  5. mac 端口转发方案

    mac 端口映射 好坑 osx10.10mac移除了ipfw改用pfpf以前没用过 查文档mac的 pf语法,没有找到.bsd的倒是很全,心喜拿来一试.http://www.openbsd.org/f ...

  6. Smali语法编程

    Smali背景: Smali,Baksmali分别是指安卓系统里的Java虚拟机(Dalvik)所使用的一种.dex格式文件的汇编器,反汇编器.其语法是一种宽松式的Jasmin/dedexer语法,而 ...

  7. Android开发工具全面转向Android Studio(3)——AS project/module的目录结构(与Eclipse对比)

    如果AS完全还没摸懂的,建议先看下Android开发工具全面转向Android Studio(2)——AS project/module的CRUD. 注:以下以Windows平台为标准,AS以目前最新 ...

  8. ebtables hook

    1 概述 netfliter框架不仅仅在ipv4中有应用,bridge,ipv4,ipv6,decnet 这四种协议中都有应用,其中ipv4中又分开了arp和ip的两种 其实netfliter是个大的 ...

  9. DSP(1) -- 离散时间信号的序列类型

    1.单位采样序列δ(n):在MATLAB 中函数zeros(1,N)产生一个由N个零组成的列向量.它可用来实现有限区间的δ(n).然而,更高明的方法是利用逻辑关系式n==0来实现δ(n). 2.单位阶 ...

  10. LeetCode(97) Interleaving String

    题目 Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example, Given: ...