Windows服务与Windows窗体在同一过程中
我有一个总结,可以作为Windows服务来控制套接字连接和其他内容。
另外,还有另一个Windows窗体应用程序用于控制和配置此服务(带有启动,停止,带有配置参数的显示窗体的系统托盘)。
我正在使用.net远程处理来完成IPC,但是现在我想显示一些实际流量和其他报告,而远程处理将无法满足我的性能要求。因此,我想将两个应用程序合并为一个。
这是问题所在:
当我从Windows服务启动表单时,什么也没发生。在Google上搜索,我发现必须右键单击该服务,转到"登录",然后选中"允许服务与桌面交互"选项。由于我不想让我的用户这样做,因此我在安装期间再次搜索了一些代码以在用户的regedit中设置此选项。问题在于,即使设置了此选项,它也不起作用。我必须打开服务的"登录"选项(已选中),取消选中后再次检查。
那么,如何解决呢?如何在同一进程中使带有systray控件的Windows服务对所有登录用户可用的最佳方法?
更新:谢谢你们到目前为止的评论。我同意使用IPC更好,并且我知道混合Windows服务和用户界面很不好。即使,我想知道该怎么做。
解决方案
使用我们选择的技术进行通信的两个独立过程。使用UI服务是一个坏主意。不要走这条路,你会后悔的。
通过一个简单的套接字连接进行服务通信可以很好地记录服务协议,并使其保持尽可能的简单,并且比我们想象的要容易。
实际上,我们不应将服务与管理UI耦合。
我同意格雷格。也许我们可以研究另一种IPC机制。也许使用套接字和我们自己的协议。或者,如果服务控制应用程序只能控制本地计算机上的服务,则可以使用命名管道(甚至更快)。
我们只需要创建一个线程来执行应用程序事件就可以了。
像这样(带有CLR的C ++的源代码,但是我们可以在C#中实现):
ref class RunWindow{ public: static void MakeWindow(Object^ data) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); Application::Run(gcnew TMainForm()); }; };
并在主线程中创建线程
int main(array<System::String ^> ^args) { bool bService = RunAsService(L"SimpleServiceWithIconInTrayAndWindow"); if (bService) { System::Threading::Thread ^thread = gcnew System::Threading::Thread(gcnew ParameterizedThreadStart(RunWindow::MakeWindow)); thread->Start(); ServiceBase::Run(gcnew simpleWinService()); Application::Exit(); } else { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); // Create the main window and run it Application::Run(gcnew TMainForm()); } return 0; }
交互式服务的主要问题是:
- 安全性-其他进程可以通过其消息泵向其发送消息,从而获得对SYSTEM / LOCAL进程的访问权限。
- 不完整-交互式服务永远不会看到外壳消息,因此无法与通知区域图标进行交互。
我们通常使用TCP和UDP连接将信息从服务传递到其他exe,在某些情况下还传递给MSMQ。
这是混合服务和表格的一种方式
http://www.codeproject.com/KB/system/SystemTrayIconInSvc.aspx
我从本文中了解了如何执行此操作(单击"方法"表中的"更改"链接)。
string wmiPath = "Win32_Service.Name='" + SERVICE_NAME + "'"; using (ManagementObject service = new ManagementObject(wmiPath)) { object[] parameters = new object[11]; parameters[5] = true; // Enable desktop interaction service.InvokeMethod("Change", parameters); }
我有几个步骤的解决方案,这是计划
- 我们将不使用Windows窗体创建服务项目,而是将创建包含Windows Service项目,Windows窗体项目和安装项目的Visual Studio解决方案。
- 想法是拥有一个数据库或者文件或者任何我们愿意存储的数据,其中我们将存储Windows服务将始终运行的参数。因此,Windows服务和Windows窗体应用程序应该能够修改和检索数据。
- 在Windows应用程序的主窗体中,将一个NotifyIcon拖放到窗体上,在属性选项卡中,浏览并选择一个.ico图像(我们可以在visual studio中复制一个图像,但这是另一个主题,我们可以在Google上找到或者与我联系),当我们运行该应用程序并且主窗体处于活动状态或者显示该窗体时,它将显示在系统托盘中,请尝试运行该应用程序。
- 将它们都添加为解决方案的安装项目中的输出。要将项目添加到安装项目中,它们必须处于同一解决方案中。右键单击解决方案资源管理器中的安装项目,突出显示添加,然后选择项目输出,添加Windows服务和Windows窗体输出,我们将在解决方案资源管理器中的安装项目下看到它们。
- 添加Windows服务的意义远不止于此,但这也是Google的另一主题
- 为Windows应用程序创建快捷方式并将其添加到启动文件夹也是Google的另一个主题,或者与我联系。注意以这样的方式编写表单:关闭按钮不显示,并且表单变为Me.visible = false,然后双击系统任务栏中的图标是设置me.visible = true的唯一方法。计算机启动,Windows窗体应用程序也已启动,并且visible会立即设置为false,但是由于它具有带有图标图像的notifyicon,它将显示在系统托盘中,并双击它可以使该窗体可见以编辑设置存储该服务时,该服务也会自动启动,因为我们可以在设置项目中设置服务时对其进行设置。我的邮件是[email protected],可以使用屏幕截图获得更好的插图,并进行完整说明