项目笔记---Windows Service调用Windows API问题

概要

  此文来自于最近一个“诡异”的Windows API调用发现Windows Service在调用某些Windows API的过程中失效,在经过漫长的Baidu,之后终于在StackOverFlow上找到了答案,今天希望把这个问题记录下来,方便大家Baidu  -。-

需求是什么?

  注:PDA一端通过Socket传输一条一维码(如1231223123123123),服务端接收到消息后,在当前(即当前有焦点的任何窗口)模拟键盘敲击一维码。

  最开始服务端是用WinForm实现的,测试成功,所以就想当然希望将服务端重构成Windows服务,实现后台监听并处理的功能,可是事与愿违,各位别着急,请继续往下看。

代码实现及问题是什么?

  Socket通讯我是用《异步Socket通讯》实现的,这里不详细介绍,先将模拟键盘的代码贴出来,此代码在Windows Form下测试可用:

    internal class Win32API
    {
        #region Constant
        private const uint KEYEVENTF_EXTENDEDKEY = 0x1;
        private const uint KEYEVENTF_KEYUP = 0x2;
        #endregion

        #region Public Property
        public static IServiceLog Log
        {
            get;
            set;
        }
        #endregion

        #region External Import
        /// <summary>
        /// Keybd_events the specified b vk.
        /// </summary>
        /// <param name="bVk">The b vk.</param>
        /// <param name="bScan">The b scan.</param>
        /// <param name="dwFlags">The dw flags.</param>
        /// <param name="dwExtraInfo">The dw extra information.</param>
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

        /// <summary>
        /// Messages the box.
        /// </summary>
        /// <param name="h">The h.</param>
        /// <param name="m">The m.</param>
        /// <param name="c">The c.</param>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int MessageBox(int h, string m, string c, int type);

        /// <summary>
        /// Gets the focus.
        /// </summary>
        /// <returns></returns>
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern IntPtr GetFocus();

        #endregion

        #region Public Method
        /// <summary>
        /// Sends the key.
        /// </summary>
        /// <param name="str">The string.</param>
        public static void SendKey(string str)
        {
            var charray = str.ToCharArray();
            for (int i = 0; i < charray.Length; i++)
            {
                CharToInt(charray[i]);
            }
            KeyBoardDo(13, 0);
        }

        #endregion

        #region Private Method
        /// <summary>
        /// Keys the board do.
        /// </summary>
        /// <param name="key">The key.</param>
        private static void KeyBoardDo(int[] key)
        {
            foreach (int k in key)
            {
                keybd_event((byte)k, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
            }
            foreach (int k in key)
            {
                keybd_event((byte)k, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
            }
        }

        /// <summary>
        /// Keys the board do.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="sheft">The sheft.</param>
        private static void KeyBoardDo(int key, int sheft)
        {
            Log.WriteInfo("KeyBoard Simulate Char: " + key);
            if (sheft == 16)
            {
                keybd_event((byte)sheft, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
                System.Threading.Thread.Sleep(10);
            }
            keybd_event((byte)key, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
            System.Threading.Thread.Sleep(10);
            keybd_event((byte)key, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
            System.Threading.Thread.Sleep(10);
            if (sheft == 16)
            {
                keybd_event((byte)sheft, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
                System.Threading.Thread.Sleep(10);
            }
        }

        /// <summary>
        /// Characters to int.
        /// </summary>
        /// <param name="ch">The ch.</param>
        /// <returns></returns>
        private static int CharToInt(char ch)
        {
            int chint = 32;
            int sheft = 16;
            switch (ch)
            {
                case ‘0‘:
                    chint = 48;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘1‘:
                    chint = 49;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘2‘:
                    chint = 50;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘3‘:
                    chint = 51;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘4‘:
                    chint = 52;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘5‘:
                    chint = 53;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘6‘:
                    chint = 54;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘7‘:
                    chint = 55;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘8‘:
                    chint = 56;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘9‘:
                    chint = 57;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘A‘:
                    chint = 65;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘B‘:
                    chint = 66;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘C‘:
                    chint = 67;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘D‘:
                    chint = 68;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘E‘:
                    chint = 69;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘F‘:
                    chint = 70;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘G‘:
                    chint = 71;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘H‘:
                    chint = 72;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘I‘:
                    chint = 73;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘J‘:
                    chint = 74;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘K‘:
                    chint = 75;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘L‘:
                    chint = 76;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘M‘:
                    chint = 77;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘N‘:
                    chint = 78;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘O‘:
                    chint = 79;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘P‘:
                    chint = 80;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘Q‘:
                    chint = 81;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘R‘:
                    chint = 82;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘S‘:
                    chint = 83;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘T‘:
                    chint = 84;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘U‘:
                    chint = 85;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘V‘:
                    chint = 86;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘W‘:
                    chint = 87;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘X‘:
                    chint = 88;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘Y‘:
                    chint = 89;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘Z‘:
                    chint = 90;
                    KeyBoardDo(chint, sheft);
                    break;
                case ‘a‘:
                    chint = 65;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘b‘:
                    chint = 66;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘c‘:
                    chint = 67;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘d‘:
                    chint = 68;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘e‘:
                    chint = 69;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘f‘:
                    chint = 70;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘g‘:
                    chint = 71;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘h‘:
                    chint = 72;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘i‘:
                    chint = 73;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘j‘:
                    chint = 74;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘k‘:
                    chint = 75;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘l‘:
                    chint = 76;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘m‘:
                    chint = 77;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘n‘:
                    chint = 78;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘o‘:
                    chint = 79;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘p‘:
                    chint = 80;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘q‘:
                    chint = 81;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘r‘:
                    chint = 82;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘s‘:
                    chint = 83;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘t‘:
                    chint = 84;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘u‘:
                    chint = 85;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘v‘:
                    chint = 86;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘w‘:
                    chint = 87;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘x‘:
                    chint = 88;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘y‘:
                    chint = 89;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘z‘:
                    chint = 90;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘;‘:
                    chint = 186;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘=‘:
                    chint = 187;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘,‘:
                    chint = 188;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘-‘:
                    chint = 189;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘.‘:
                    chint = 190;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘/‘:
                    chint = 191;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘`‘:
                    chint = 192;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘[‘:
                    chint = 219;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘]‘:
                    chint = 221;
                    KeyBoardDo(chint, 0);
                    break;
                case ‘\‘‘:
                    chint = 222;
                    KeyBoardDo(chint, 0);
                    break;
            }
            return chint;
        }
        #endregion 

    }

  同样的代码在Windows Service调用没有任何效果,原因就出在这里:Session 0 Isolation,简而言之就是在Win XP以及之前的windows服务(系统服务和用户编写的服务)都运行在最高权限的Session 0 中,但是在Vista以及之后的系统中用户所编写的服务被隔离开,为的是系统安全性考虑,被隔离开的服务中受影响的是一些基于图形界面的系统调用都将失效,如“User32.dll”中的MessageBox调用,同时也包含本文中的模拟键盘的keybd_event调用。

有兴趣的朋友可以自行测试下,原理很简单,这里就不给出更多的代码了。

注:Vista之后系统服务权限图。

结语

说点题外话,其实这个问题就是一句话的事:Win7下Windows服务不能调用键盘模拟事件,为什么在百度搜来搜去,基本没有什么有价值的信息,包括CSDN等等。后来,不得不开着FQ软件去Google,或者再去StackOverFlow提问,搜索问题,这里也不去抱怨什么,只希望作为码农的我以及跟我一样的人能更熟练的掌握英语,Happy To Search On Google.

引用

Session 0 Isolation: https://msdn.microsoft.com/en-us/library/windows/hardware/dn653293(v=vs.85).aspx

StackOverFlow Discuss:http://stackoverflow.com/questions/16959963/how-to-reset-windows-idle-timer-through-a-windows-service

时间: 2025-01-22 19:34:14

项目笔记---Windows Service调用Windows API问题的相关文章

C# 编写Windows Service(windows服务程序)

Windows Service简介: 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序.Windows服务程序虽然是可执行的,但是它不像一般的可执行文件通过双击就能开始运行了,它必须有特定的启动方式.这些启动方式包括了自动启动和手动启动两种.对于自动启动的Windows服务程序,它们在Windows启动或是重启之后用户登录之前就开始执行了.只要你将相应的Windows服务程序注册到服务控制管理器(Service Control Manager)中,并将其启动

C# 编写Windows Service(windows服务程序)【转载】

[转]http://www.cnblogs.com/bluestorm/p/3510398.html Windows Service简介: 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序.Windows服务程序虽然是可执行的,但是它不像一般的可执行文件通过双击就能开始运行了,它必须有特定的启动方式.这些启动方式包括了自动启动和手动启动两种.对于自动启动的Windows服务程序,它们在Windows启动或是重启之后用户登录之前就开始执行了.只要你将相应的Wi

c#创建Windows service (Windows 服务)基础教程

转自:http://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html 1)创建Windows service项目 二.创建服务安装程序 1)添加安装程序 之后我们可以看到上图,自动为我们创建了ProjectInstaller.cs以及2个安装的组件. 2)修改安装服务名 右键serviceInsraller1,选择属性,将ServiceName的值改为ServiceTest. 3)修改安装权限 右键serviceProcessInsral

C# 创建Windows Service(Windows服务)程序

本文介绍了如何用C#创建.安装.启动.监控.卸载简单的Windows Service 的内容步骤和注意事项. 一.创建一个Windows Service 1)创建Windows Service项目 2)对Service重命名 将Service1重命名为你服务名称,这里我们命名为ServiceTest. 二.创建服务安装程序 1)添加安装程序 之后我们可以看到上图,自动为我们创建了ProjectInstaller.cs以及2个安装的组件. 2)修改安装服务名 右键serviceInsraller1

【Windows Service】Windows Service在Visual Studio中安装、调试

目录结构: contents structure [-] 创建Windows服务 配置 安装Windows服务 在Visual Studio中调试 常见问题 最近写了一个TCP连接的程序,由于这种通信协议不同于HTTP协议,因此还不能部署到网站上面,于是就用到了Window服务.接下面笔者介绍一下在Visual Studio中如何安装.调试Windows服务.笔者的Visual studio版本为2012,window版本为win7. 1.创建Windows服务 这时候点击“启动”按钮,会提示我

C# Windows Service(Windows服务)相关

https://www.cnblogs.com/charlie-chen2016/p/8031774.html 这是一个备份数据库的服务,逻辑很简单,就是通过定时器实现在特定的时间执行SQL语句备份数据库,并将每一步操作的情况写入日志文件. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using S

HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器

HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道和一些元数据,这些是和你的视频或者音频控件绑定到一块的,这样才形成了一个完整的播放组件. 浏览器支持情况: 浏览器 支持情况 编解码器 Chrome 3.0 Theora . Vorbis .Ogg H.264 . AAC .MPEG4 FireFox 3.5 Theora . Vorbis .Og

Windows service 学习

最近看了看windows service, 1. 找到了一个帖子:http://blog.csdn.net/knight94/article/details/627298 2. At the end of the link http://www.cnblogs.com/Googler/archive/2013/07/23/3208354.html , there is a sentance: The "Interact with Desktop" option is not suppo

C#调用Windows API详解(上)

以前我写过通过WMI来获取有关系统信息的系列文章,确实通过WMI能够恨轻易地实现很多我们想实现的功能,不过有些情况下我们很难利用WMI来实现一些 复杂的功能,比如最近我做的一个项目,其中有一个功能就是要更改系统当前时间,利用WMI就很难实现(我没有找到相关的方法),还有一些其它方面的功能, 也比较难以通过WMI来实现,也许是WMI需要较高的权限才能执行的原因吧.所以,尽管我们不愿意,但是又不得不通过调用Windows 的API来实现.本文的目的就是讲述如何在C#中调用Windows的系统API.