由于个人需要,想找一个键盘记录的程序,从网上下载了很多,多数都是需要注册的,另外也多被杀软查杀。于是决定自己写一个,如果作为一个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. javascript (js)判断手机号码中国移动、中国联通、中国电信

    我国使用的手机号码为11位,其中各段有不同的编码方向:前3位———网络识别号:第4-7位———地区编码:第8-11位———用户号码. 中国移动134.135.136.137.138.139.150.1 ...

  2. sql server 还原数据库后,删除用户,提示数据库主体在该数据库中拥有架构,无法删除解决方法

    将另一台服务器上的数据库备份文件,在现在用的这台服务器上还原之后,再创建相同的用户名,提示用户已存在 想将之前的用户先删除掉,却提示“数据库主体在该数据库中拥有架构,无法删除解决方法” 在网上找到方法 ...

  3. git分支管理一

    1.创建本地分支 local_branch git branch local_branch 2.创建本地分支local_branch 并切换到local_branch分支 git checkout - ...

  4. git资料图

  5. h5整理--详解css的相对定位和绝对定位

    浏览器默认状态下position的属性默认值是static也就是没有定位,元素出现在正常的文档流中,这个时候给元素设置的left,right.bottom.top这些偏移属性是没有效果的,不会生效: ...

  6. 一个未解决的samba问题

    话说,现在的打复印扫描一体机的扫描功能十分丰富,扫描后的文件可以通过邮件发送,可以发到windows的共享.一直用着windows共享的方式,但是windows系统占用的内存还是略大,想把这个共享放到 ...

  7. final、finally、finalize的区别

    看C#知识点的时候发现的问题 1.final 修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 abstract的,又被声明为f ...

  8. Linux C++ 开发常用工具,常用指令工作手册

    vim常用: :set nu显示行数 :set mouse=a 鼠标滑动屏幕,:set ic :set noic 忽略不忽略大小写 /word_to_search\c \c表示忽略大小写 c小写忽略, ...

  9. 《笨办法学C》笔记之指针

    C语言编程主要操作的对象就是指针. 指针从哪里来 指针就是表示内存存储区域的一组数值,使用%p格式化字符串. Linux系统会为程序维护两个临时变量存储位置:栈.堆.栈的空间少,栈通常在用户更高的地址 ...

  10. 安装完ODAC,出现ORA-12560:TNS:协议适配器错误 12541 无监听程序的解决

    进入系统环境变量设置,查看Path路径,发现D:\oracle\product\11.2.0\client_1等路径放到了oracle11g数据库路径前面,将新加入的路径置后即可解决ORA-12560 ...