

結局のところ出来ないという結論になるのでしょうか？  
何か裏技みたいなもので何とかなるのでしょうか？

**Program.cs**

[code]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace test
    {
        static class Program
        {
            /// <summary>
            /// アプリケーションのメイン エントリ ポイントです。
            /// </summary>
            static void Main()
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
                {
                    new Service1()
                };
                ServiceBase.Run(ServicesToRun);
            }
        }
    }
    
[/code]

**Service1.cs**

[code]

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.Threading.Tasks;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.IO;
    using OpenCvSharp;
    using OpenCvSharp.Internal;
    using System.Windows;
    using System.Windows.Input;
    using System.Timers;
    
    namespace test
    {
        public partial class Service1 : ServiceBase
        {
            static Timer timer = new Timer();
            static InterceptKeyboard interceptKeyboard = new InterceptKeyboard();
    
            public Service1()
            {
                InitializeComponent();
            }
    
            protected override void OnStart(string[] args)
            {
                timer.Interval = 100;
                timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
                timer.AutoReset = false;
                timer.Enabled = true;
                timer.Start();
                interceptKeyboard.Hook();
            }
    
            public void OnTimer(object sender, ElapsedEventArgs args)
            {
            }
            protected override void OnStop()
            {
                interceptKeyboard.UnHook();
            }
            private static void InterceptKeyboard_KeyUpEvent(object sender, InterceptKeyboard.OriginalKeyEventArg e)
            {
                File.WriteAllText(@"C:\test\1.txt", e.KeyCode.ToString());
            }
    
            private static void InterceptKeyboard_KeyDownEvent(object sender, InterceptKeyboard.OriginalKeyEventArg e)
            {
                File.WriteAllText(@"C:\test\2.txt", e.KeyCode.ToString());
            }
        }
    
        abstract class AbstractInterceptKeyboard
        {
            #region Win32 Constants
            protected const int WH_KEYBOARD_LL = 0x000D;
            protected const int WM_KEYDOWN = 0x0100;
            protected const int WM_KEYUP = 0x0101;
            protected const int WM_SYSKEYDOWN = 0x0104;
            protected const int WM_SYSKEYUP = 0x0105;
            #endregion
    
            #region Win32API Structures
            [StructLayout(LayoutKind.Sequential)]
            public class KBDLLHOOKSTRUCT
            {
                public uint vkCode;
                public uint scanCode;
                public KBDLLHOOKSTRUCTFlags flags;
                public uint time;
                public UIntPtr dwExtraInfo;
            }
    
            [Flags]
            public enum KBDLLHOOKSTRUCTFlags : uint
            {
                KEYEVENTF_EXTENDEDKEY = 0x0001,
                KEYEVENTF_KEYUP = 0x0002,
                KEYEVENTF_SCANCODE = 0x0008,
                KEYEVENTF_UNICODE = 0x0004,
            }
            #endregion
    
            #region Win32 Methods
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr GetModuleHandle(string lpModuleName);
            #endregion
    
            #region Delegate
            private delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
            #endregion
    
            #region Fields
            private KeyboardProc proc;
            private IntPtr hookId = IntPtr.Zero;
            #endregion
    
            public void Hook()
            {
                if (hookId == IntPtr.Zero)
                {
                    proc = HookProcedure;
                    using (var curProcess = Process.GetCurrentProcess())
                    {
                        using (ProcessModule curModule = curProcess.MainModule)
                        {
                            hookId = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
                        }
                    }
                }
            }
    
            public void UnHook()
            {
                UnhookWindowsHookEx(hookId);
                hookId = IntPtr.Zero;
            }
    
            public virtual IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam)
            {
                return CallNextHookEx(hookId, nCode, wParam, lParam);
            }
        }
        class InterceptKeyboard : AbstractInterceptKeyboard
        {
            #region InputEvent
            public class OriginalKeyEventArg : EventArgs
            {
                public int KeyCode { get; }
    
                public OriginalKeyEventArg(int keyCode)
                {
                    KeyCode = keyCode;
                }
            }
            public delegate void KeyEventHandler(object sender, OriginalKeyEventArg e);
            public event KeyEventHandler KeyDownEvent;
            public event KeyEventHandler KeyUpEvent;
    
            protected void OnKeyDownEvent(int keyCode)
            {
                KeyDownEvent?.Invoke(this, new OriginalKeyEventArg(keyCode));
            }
            protected void OnKeyUpEvent(int keyCode)
            {
                KeyUpEvent?.Invoke(this, new OriginalKeyEventArg(keyCode));
            }
            #endregion
    
            public override IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam)
            {
                if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
                {
                    var kb = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                    var vkCode = (int)kb.vkCode;
                    OnKeyDownEvent(vkCode);
                }
                else if (nCode >= 0 && (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP))
                {
                    var kb = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                    var vkCode = (int)kb.vkCode;
                    OnKeyUpEvent(vkCode);
                }
    
                return base.HookProcedure(nCode, wParam, lParam);
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2021-02-11T06:16:43.093
73928
2021-02-11T08:08:50.300
2021-02-11T07:28:50.983
3068
43916
question
c# windows-10
Windows 10 で動くサービスプログラムにて入力したキーコードを取得出来ません。


コメントにあるように、Windows Vistaから導入された「セッション 0
分離」というもので、「サービス」や「プリンタドライバ」「ユーザーモードのデバイスドライバー」と言ったものがユーザーインタフェースを持たないプロセスのグループとして分離した環境で実行されます。  
[Application Compatibility - Session 0
Isolation](https://techcommunity.microsoft.com/t5/ask-the-performance-
team/application-compatibility-session-0-isolation/ba-p/372361)  
[4.7 セッション 0 の分離](https://docs.microsoft.com/ja-jp/previous-
versions/msdn10/dd871151\(v=msdn.10\))  
対処としては、この記事の最後に「セッション 0 の分離への対応」ということで、概要が説明されています。

記事の中頃に「対話型サービス検出サービス」という説明があり、以前との互換性のための機能が用意されているとありますが、Windows8.0で一時仕様が変わったり、Windows10ではテストされていない(動いていない)のでは？という記事もあります。  
[トラブルシューター泣かせのWindowsの仕様変更──忘れられた互換性機能？
(1/2)](https://www.atmarkit.co.jp/ait/articles/1704/11/news015.html)

デバイスドライバについては別の記事があります。  
[UMDF ドライバーに対するセッション 0 のガイドライン](https://docs.microsoft.com/ja-jp/windows-
hardware/drivers/wdf/session-zero-guidelines-for-umdf-drivers)

* * *

いずれにしてもセッション0で実行されるプログラムでは「ユーザーインタフェース」「ウインドウメッセージ」「画面上のプロパティ」「ユーザーローカルオブジェクト」を扱うことはできません。

そのため、「ユーザーインタフェース」「ウインドウメッセージ」に含まれる「キーボード」や「マウス」に関する何かを直接扱うことはできません。

それらを扱う部分をユーザープロセスとして分離させて、サービスとプロセス間通信しながら協同で目的の機能を実現する方法があるでしょう。

上記紹介記事の最後に概要説明されていることとか、以下の記事で解説されているような内容です。  
[IPA ISEC セキュア・プログラミング講座
8-2.プロセス間通信とバックドア](https://www.ipa.go.jp/security/awareness/vendor/programmingv1/b08_02.html)

キーボードで操作しない別の方法とかであれば、上記紹介も含むこんな記事があります。  
[(セッション0の分離)サービスからexeを実行する方法](https://ja.stackoverflow.com/q/39370/26370)

* * *

キーボード操作にこだわって、しかもプロセス分離とかしたくないなら、サービスとして作るのは諦めてユーザープロセスとして動作させることになります。

こんな記事のように、ログオンしたら自動で起動されるようにしておけば良いでしょう。そんな風になっているプログラムはいくつもあります。  
[Bginfoを全ユーザログオン時に実行する方法【実装方法】](https://syachiku.net/bginfo-autoexec/)

あるいは、処理自身を C# ではなく AutoHotKey のようなカスタマイズユーティリティで記述して組み込むという方法も考えられます。  
[快適キーボード操作のためのキーカスタマイズ 〜Windows編〜](https://knowledge.sakura.ad.jp/23305/)


CC BY-SA 4.0
2021-02-11T08:08:50.300
73930
2021-02-11T08:08:50.300
26370
73928
answer