项目笔记---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
作者:Stephen Cui
出处:http://www.cnblogs.com/cuiyansong
版权声明:文章属于本人及博客园共有,凡是没有标注[转载]的,请在文章末尾加入我的博客地址。
如果您觉得文章写的还不错,请点击“推荐一下”,谢谢。