微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从作为可以与用户交互的SYSTEM运行的服务启动应用程序

我目前有一个单一的应用程序,需要从我在.net 3.5编码的Windows服务启动。 此应用程序当前以运行该服务的用户身份运行,在我的情况下是SYstem用户。 如果以SYstem用户身份运行,则不会将应用程序显示用户桌面。 思考? build议?

//constructor private Process ETCHNotify = new Process(); //StartService() ETCHNotify.StartInfo.FileName = baseDir + "\EtchNotify.exe"; ETCHNotify.StartInfo.UseShellExecute = false; //BackgroundWorkerThread_DoWork() if (!systemData.GetUserName().Equals("")) { // start ETCHNotify try { ETCHNotify.Start(); } catch (Exception ex) { systemData.Run("ERR: Notify can't start: " + ex.Message); } }

我只执行try / catch如果函数我已经写了GetUserName()(它决定运行explorer.exe的用户用户名)不是null

再次重申:所需的function是,这启动了ETCHNotify的状态,允许它与当前login的用户进行交互,由GetUserName()

在.NET中获取用户的Exchange服务器和电子邮件地址

如何导出Windows系统和应用程序事件日志?

有没有办法使row.DefaultCellStyle.BackColor固定,尽pipe重绘?

C# – 使用正则expression式与TextBox.Validating

如何在VB.NET中的用户计算机上安装字体,以便Word等应用程序可以使用它?

向GAC注册/安装大会的“正确”方式是什么?

为什么Microsoft.Build.Evaluation在64位PC上将$(ProgramFiles)评估为“c: program files”?

自动更新C#程序

我应该在哪里存储适用于非漫游用户的机器范围的应用程序设置?

CultureInfo.CurrentCulture.DateTimeFormat.AbbreviatedDayNames问题

一些发现的贴子( 这个和这个 )

请注意,从Windows Vista开始,服务严禁与用户直接交互

重要提示:从Windows Vista开始,服务不能直接与用户交互。 因此,标题为“使用交互式服务”一节中提到的技术不应在新代码中使用。

这个“特征”已经被打破了,而传统的观点认为你不应该依赖它。 服务并不意味着提供一个UI或允许任何类型的直接用户交互。 微软一直警告说,从Windows NT的早期开始就可以避免这个功能,因为可能存在安全风险。

有一些可能的解决方法,但是,如果你绝对必须有这个功能。 但我强烈建议您仔细考虑其必要性,并为您的服务探索替代设计。

使用WTSEnumerateSessions找到正确的桌面,然后CreateProcessAsUser在该桌面上启动应用程序(将其作为STARTUPINFO结构的一部分传递给桌面的句柄)是正确的。

不过,我强烈建议不要这样做。 在一些环境中,比如终端服务器主机上有许多活跃的用户,确定哪个桌面是“主动”的是不容易的,甚至可能是不可能的。

更传统的方法是在全球启动组中为您的服务添加一个小型客户端应用程序的快捷方式。 这个应用程序随后将随每个用户会话一起启动,并可用于启动其他应用程序(如果需要的话),而不需要任何用户证书,会话和/或桌面的杂耍。

我不打算回答这个问题,因为你已经回答了这个问题,(现在是二十五年了,现在呢?)但是总有那些人在寻找同样的话题,并且阅读答案。 。

为了让我的服务与桌面互动,无论是桌面,还是多台桌面,甚至服务甚至在同一台计算机上运行的桌面应用程序! 没有关系到我在这里得到的东西…我不会在细节上让你感到厌烦,我只是把肉和土豆给你,如果你想看更多的东西,请告诉我。

好。 我做的第一件事就是创建一个广告服务 。 这是服务运行的线程,打开一个UDP套接字来监听网络上的广播。 然后,使用同一段代码,我将它与客户端应用程序共享,但它调用Advertise.CLIENT ,而不是Advertise.SERVER … CLIENT打开端口,我期望该服务在,并广播消息,“你好…有没有人在那里?”,询问他们是否有任何服务器在监听,如果是的话,回复到这个IP地址,你的电脑名称,IP地址和端口#,我可以找到.NET Remoting Services …“,然后等待一小段超时时间,收集它所得到的响应,如果它超过一个,则向用户显示一个对话框和一个响应的服务列表。然后客户端选择一个,或者,如果只有一个响应,它将调用Connect( (TserverResponse) res);这样,连接起来。此时,服务器正在使用远程服务,WellKNownClientType和WellKNownserverType把自己放在那里…

我不觉得你对我的“自动定位器”太感兴趣了,因为很多人都对UDP皱眉,甚至当你的应用在大型网络上开始播放的时候更是如此。 所以,我假设你会对我的RemotingHelper更感兴趣,让客户端连接到服务器。 它看起来像这样:

public static Object Getobject(Type type) { try { if(_wellKNownTypes == null) { InitTypeCache(); } WellKNownClientTypeEntry entr = (WellKNownClientTypeEntry)_wellKNownTypes[type]; if(entr == null) { throw new RemotingException("Type not found!"); } return System.Activator.Getobject(entr.ObjectType,entr.ObjectUrl); } catch(System.Net.sockets.socketException sex) { DebugHelper.Debug.OutputDebugString("SocketException occured in RemotingHelper::Getobject(). Error: {0}.",sex.Message); disconnect(); if(Connect()) { return Getobject(type); } } return null; } private static void InitTypeCache() { if(m_Advertiseserver == null) { throw new RemotingException("Advertisementserver cannot be null when connecting to a server."); } _wellKNownTypes = new Dictionary<Type,WellKNownClientTypeEntry>(); Dictionary<string,object> channelProperties = new Dictionary<string,object>(); channelProperties["port"] = 0; channelProperties["name"] = m_Advertiseserver.ChannelName; Dictionary<string,object> b@R_207_4045@terProperties = new Dictionary<string,object>(); b@R_207_4045@terProperties["typeFilterLevel"] = "Full"; if(Environment.UserInteractive) { BinaryserverFormatterSinkProvider b@R_207_4045@terProvider = new BinaryserverFormatterSinkProvider(b@R_207_4045@terProperties,null); _serverChannel = new TcpserverChannel(channelProperties,b@R_207_4045@terProvider); // LEF: Only if we are coming form OUTSIDE the SERVICE do we want to register the channel,since the SERVICE already has this // channel registered in this AppDomain. ChannelServices.RegisterChannel(_serverChannel,false); } System.Diagnostics.Debug.Write(string.Format("Registering: {0}...n",typeof(IPawnStatServiceStatus))); RegisterType(typeof(IPawnStatServiceStatus),m_Advertiseserver.RunningStatusURL.ToString()); System.Diagnostics.Debug.Write(string.Format("Registering: {0}...n",typeof(IPawnStatService))); RegisterType(typeof(IPawnStatService),m_Advertiseserver.RunningserverURL.ToString()); System.Diagnostics.Debug.Write(string.Format("Registering: {0}...n",typeof(IServiceConfiguration))); RegisterType(typeof(IServiceConfiguration),m_Advertiseserver.RunningConfigURL.ToString()); } [SecurityPermission(SecurityAction.Demand,Flags=SecurityPermissionFlag.RemotingConfiguration,RemotingConfiguration=true)] public static void RegisterType(Type type,string serviceUrl) { WellKNownClientTypeEntry clientType = new WellKNownClientTypeEntry(type,serviceUrl); if(clientType != RemotingConfiguration.IsWellKNownClientType(type)) { RemotingConfiguration.RegisterWellKNownClientType(clientType); } _wellKNownTypes[type] = clientType; } public static bool Connect() { // Init the Advertisement Service,and Locate any listening services out there... m_Advertiseserver.InitClient(); if(m_Advertiseserver.LocateServices(iTimeout)) { if(!Connected) { bConnected = true; } } else { bConnected = false; } return Connected; } public static void disconnect() { if(_wellKNownTypes != null) { _wellKNownTypes.Clear(); } _wellKNownTypes = null; if(_serverChannel != null) { if(Environment.UserInteractive) { // LEF: Don't unregister the channel,because we are running from the service,and we don't want to unregister the channel... ChannelServices.UnregisterChannel(_serverChannel); // LEF: If we are coming from the SERVICE,we do *NOT* want to unregister the channel,since it is already registered! _serverChannel = null; } } bConnected = false; } }

所以,这是我的远程代码的肉,让我写一个客户端,不必知道服务的安装位置,或在网络上运行多少服务。 这使我可以通过网络或本地机器与它进行通信。 让两个或两个以上的人运行应用程序并不是一个问题,但是,你的可能。 现在,我有一些复杂的回调代码,我在那里注册事件,通过远程通道,所以我必须有代码来检查客户端是否连接,然后才向客户端发送事件。 此外,如果您正在运行多个用户,则可能不想使用Singleton对象。 这对我来说很好,因为服务器拥有这些对象,并且它们是服务器的所有东西。 所以,我的STATS对象,例如,是一个单身人士。 没有理由为每个连接创建一个实例,当每个人都看到相同的数据,对不对?

如有必要,我可以提供更多的代码块。 当然,这是什么使得这项工作的总体情况的一小部分…更不用说订阅提供者,以及所有这些。

为了完整起见,我将包含代码块,以便在过程的整个过程中保持您的服务连接。

public override object InitializeLifetimeService() { ILease lease = (ILease)base.InitializeLifetimeService(); if(lease.CurrentState == LeaseState.Initial) { lease.InitialLeaseTime = TimeSpan.FromHours(24); lease.SponsorshipTimeout = TimeSpan.FromSeconds(30); lease.RenewOnCallTime = TimeSpan.FromHours(1); } return lease; } #region ISponsor Members [SecurityPermissionAttribute(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.Infrastructure)] public TimeSpan renewal(ILease lease) { return TimeSpan.FromHours(12); } #endregion

如果将ISponsor接口作为服务器对象的一部分包含在内,则可以实现上述代码

希望这有些有用。

当你注册你的服务时,你可以告诉它允许与桌面交互。 你可以阅读这个oldie链接http://www.codeproject.com/KB/install/cswindowsservicedesktop.aspx

此外,不要忘记,你可以有多个用户同时登录

显然,在Windows Vista和更新的与桌面交互已经变得更加困难。 阅读这个潜在的解决方案: http : //www.codeproject.com/KB/cs/ServiceDesktopInteraction.aspx

最终,为了解决这个问题,我接受了@marco的建议和他提到的帖子。 我创建的服务完全独立于与用户交互的托盘应用程序。 但是,我通过注册表“启动”方法安装了托盘应用程序。 Service安装程序现在将安装与用户交互的应用程序…这是最安全和最完整的方法

谢谢大家的帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐