首页 > 解决方案 > C# windows 服务安装后不返回剪贴板数据

问题描述

我有一个 Windows 服务程序的代码,它应该不时清除剪贴板。在控制台应用程序中对其进行测试证明它是一个工作代码(然后通过 Topshelf nuget 包将控制台应用程序变为服务)。但是将它作为服务运行它只是无法完成这项工作。经过一些基本的日志记录后,我发现 Clipboard.Hastext() (以及所有其他)在安装服务(直接从调试文件夹安装)后返回 false。我错过了什么或者应该考虑的调试和部署模式之间的区别是什么?

    public class Service
    {
        readonly Timer timer;
        object clipboardData;

        public Service()
        {
            timer = new Timer(TimeSpan.FromMinutes(1).TotalMilliseconds)
            {
                AutoReset = true
            };
            timer.Elapsed += Timer_Elapsed;
        }

        /// <summary>
        /// Checks every minute if there is any data on the clipboard.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            CurrentThreadParse(DoWork);
        }

        public void Start()
        {
            timer.Start();
        }

        public void Stop()
        {
            timer.Stop();
        }

        private void ChangeClipboardData()
        {
            if (Clipboard.ContainsText())
            {
                clipboardData = Clipboard.GetText();
                WriteChanged();
            }
            else if (Clipboard.ContainsImage())
            {
                clipboardData = Clipboard.GetImage();
                WriteChanged();
            }
            else if (Clipboard.ContainsAudio())
            {
                clipboardData = Clipboard.GetAudioStream();
                WriteChanged();
            }
            else if (Clipboard.ContainsFileDropList())
            {
                clipboardData = Clipboard.GetFileDropList();
                WriteChanged();
            }
#if DEBUG
            else
                Console.WriteLine("No change!");
#endif
        }

        private void WriteChanged()
        {
#if DEBUG
            Console.WriteLine("Clipboard data has changed!");
#endif
        }

        private object GetClipboardObject()
        {
            if (Clipboard.ContainsText())
                return Clipboard.GetText();
            else if (Clipboard.ContainsImage())
                return Clipboard.GetImage();
            else if (Clipboard.ContainsAudio())
                return Clipboard.GetAudioStream();
            else if (Clipboard.ContainsFileDropList())
                return Clipboard.GetFileDropList();
            return null;
        }

        private void ClearClipboard()
        {
            Clipboard.Clear();
            clipboardData = null;
#if DEBUG
            Console.WriteLine("Clipboard data removed!");
#endif
        }

        /// <summary>
        /// Sets the current thread as STA.
        /// </summary>
        /// <param name="threadStart">The code to run.</param>
        private void CurrentThreadParse(ThreadStart threadStart)
        {
            Thread thread = new Thread(threadStart);
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
        }

        private void DoWork()
        {
            object clipboardObject = GetClipboardObject();
            if (clipboardData == null)
            {
                ChangeClipboardData();
            }
            else if (clipboardData.Equals(clipboardObject))
            {
                ClearClipboard();
            }
            else
            {
                //The last check returned data from the clipboard, but was changed,
                //so the clipboard should not be cleared.
                ChangeClipboardData();
            }
        }
    }

完整的项目可以在这里找到:https ://github.com/profgyuri/ClipboardService

标签: c#windowswindows-servicesclipboard

解决方案


服务是不可能的。

服务在 Windows 上的单独会话中运行(会话 0)。用户始终处于不同的会话中(会话 1、2 等)。其他会话中的服务无法访问用户的剪贴板。

相反,您可以创建要在用户会话中执行的 Windows 计划任务,即Run only when user is logged on任务(链接)。时间表可以有任何重复间隔。


推荐阅读