C# Windows 服务与 Windows 窗体在同一进程中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/159076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:10:13  来源:igfitidea点击:

Windows services with windows forms in the same process

提问by andrecarlucci

I have a c# application that runs as a windows service controlling socket connections and other things. Also, there is another windows forms application to control and configure this service (systray with start, stop, show form with configuration parameters).

我有 ac# 应用程序,它作为控制套接字连接和其他东西的 Windows 服务运行。此外,还有另一个 windows 窗体应用程序来控制和配置此服务(带有启动、停止、显示带有配置参数的表单的系统托盘)。

I'm using .net remoting to do the IPC and that was fine, but now I want to show some real traffic and other reports and remoting will not meet my performance requirements. So I want to combine both applications in one.

我正在使用 .net 远程处理进行 IPC,这很好,但现在我想显示一些真实的流量和其他报告,并且远程处理无法满足我的性能要求。所以我想将两个应用程序合二为一。

Here is the problem:

这是问题所在:

When I started the form from the windows service, nothing happened. Googling around I've found that I have to right click the service, go to Log on and check the "Allow service to interact with desktop" option. Since I don't want to ask my users to do that, I got some code googling again to set this option in the user's regedit during installation time. The problem is that even setting this option, it doesn't work. I have to open the Log On options of the service (it is checked), uncheck and check again.

当我从 Windows 服务启动表单时,什么也没发生。谷歌搜索我发现我必须右键单击该服务,转到登录并选中“允许服务与桌面交互”选项。因为我不想让我的用户这样做,所以我再次搜索了一些代码,以便在安装期间在用户的 regedit 中设置此选项。问题是即使设置了这个选项,它也不起作用。我必须打开服务的登录选项(已选中),取消选中并再次选中。

So, how to solve that? How is the best way to have a windows service with a systray control in the same process, available to any user logging in?

那么,如何解决呢?在同一进程中使用系统托盘控件的 Windows 服务的最佳方式是什么,可供任何登录用户使用?

UPDATE: Thanks for the comments so far, guys. I agree it is better to use IPC and I know that it is bad to mix windows services and user interfaces. Even though, I want to know how to do that.

更新:感谢到目前为止的评论,伙计们。我同意使用 IPC 更好,我知道混合 Windows 服务和用户界面是不好的。尽管如此,我想知道如何做到这一点。

采纳答案by Greg Hurlman

Two separate processes that communicate using your technology of choice. Services with UI is a bad idea. Don't go down this road - you'll regret it.

使用您选择的技术进行通信的两个独立进程。带有 UI 的服务是个坏主意。不要走这条路——你会后悔的。

I've had very good results having service communication through a simple socket connection - document your service protocol well, keep it as simple as possible, and it'll be easier than you think.

我已经通过简单的套接字连接进行服务通信取得了非常好的结果 - 很好地记录您的服务协议,使其尽可能简单,并且它会比您想象的更容易。

回答by Quintin Robinson

In practice you should not couple your service with the management UI.

在实践中,您不应该将您的服务与管理 UI 结合起来。

回答by Peter Meyer

I agree with Greg. Perhaps you could examine a different IPC mechanism. Perhaps use sockets and your own protocol. Or, if your service control app can only control the service on the local machine, you can use named pipes (even faster).

我同意格雷格。也许您可以检查不同的 IPC 机制。也许使用套接字和您自己的协议。或者,如果您的服务控制应用程序只能控制本地机器上的服务,您可以使用命名管道(甚至更快)。

回答by CoolMagic

It is very simply - your need to create one thread for perform application events. Like this( source code for C++ with CLR, but your can make this in C#):

这很简单 - 您需要创建一个线程来执行应用程序事件。像这样(带有 CLR 的 C++ 源代码,但您可以在 C# 中实现):

ref class RunWindow{
public:
    static void MakeWindow(Object^ data)
    {
        Application::EnableVisualStyles();
        Application::SetCompatibleTextRenderingDefault(false); 

        Application::Run(gcnew TMainForm());
    };
};

And create thread in main

并在主线程中创建线程

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;
}

回答by cookre

The main problems with interactive services are:

交互式服务的主要问题是:

  • Security - other process could send it messages through its message pump, thereby gaining access to a SYSTEM/LOCAL process.

  • Incompleteness - an interactive service never sees shell messages, hence it can't interact with Notification Area icons.

  • 安全性 - 其他进程可以通过其消息泵向其发送消息,从而获得对系统/本地进程的访问权限。

  • 不完整 - 交互式服务永远不会看到 shell 消息,因此它无法与通知区域图标进行交互。

We regularly use TCP and UDP connections to pass info from services to other exes, and, in some cases, MSMQ.

我们经常使用 TCP 和 UDP 连接将信息从服务传递到其他 exe,在某些情况下,还有 MSMQ。

回答by cookre

Here is a way mixing up Services and Forms

这是一种混合服务和表单的方法

http://www.codeproject.com/KB/system/SystemTrayIconInSvc.aspx

http://www.codeproject.com/KB/system/SystemTrayIconInSvc.aspx

回答by Phil

I figured out how to do this from this article(click on the "Change" link in the Methods table).

我从这篇文章中想出了如何做到这一点(单击方法表中的“更改”链接)。

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);
}

回答by ekeolere olaide

I have the solution in a few steps, this is the plan

我有几个步骤的解决方案,这是计划

  1. we are not going to create a service project with a a windows form, instead we are going to create a visual studio solution that contains a windows service project, a windows form project and a setup project.

  2. The idea is to have a database or a file or anything you are comfortable with storing data in which you would store the parameters your windows service will always use to run. So your windows service and your windows form application should be able to modify and retrieve data from it.

  3. To the Main Form Of Your Windows Application drag and drop a NotifyIcon on the form, in the properties tab, browse and select an .ico image(You can sreate one in visual studio but that is another topic you can get on google or contact me) That it will display in the system tray when you run the application and the main form is active or shown, try it, run the application.

  4. Add both of them as outputs in the setup project of the solution. To Add a project to a setup project they must be in the same solution. Right click the setup project in the solution explorer, highlight add and then select project output, add the windows service and the windows form outputs and you will see them in the solution explorer under the setup project.

  5. adding a windows service goes further than this but that also is another topic google it

  6. Creating shortcut for the windows application and adding it to the startup folder is also another topic google or contact me.

    NOTE Program your form in such a way that the close button doesn't show and the form goes Me.visible = false and double clicking the icon in the system tray is the only way to set me.visible=true.that way anytime the computer starts up, your windows form application is also started and visible is immediately set to false but since it has a notifyicon with an icon image, it will show in the system tray and double clicking it makes the form visible to edit the settings that you are storing for the service, the service also starts automatically since you would have set it in setting up the service in the setup project. my mail is [email protected] for a better illustration using screen shots And explain in full

  1. 我们不会创建一个带有 Windows 窗体的服务项目,而是创建一个 Visual Studio 解决方案,其中包含一个 Windows 服务项目、一个 Windows 窗体项目和一个安装项目。

  2. 这个想法是拥有一个数据库或文件或任何您喜欢存储数据的东西,您将在其中存储 Windows 服务将始终用于运行的参数。因此,您的 Windows 服务和 Windows 窗体应用程序应该能够从中修改和检索数据。

  3. 在 Windows 应用程序的主窗体中,在窗体上拖放一个 NotifyIcon,在属性选项卡中,浏览并选择一个 .ico 图像(您可以在 Visual Studio 中创建一个,但这是另一个主题,您可以在 google 上获取或联系我) 当您运行应用程序并且主窗体处于活动状态或显示时,它将显示在系统托盘中,尝试一下,运行应用程序。

  4. 在解决方案的设置项目中将它们添加为输出。要将项目添加到安装项目,它们必须在同一解决方案中。右键单击解决方案资源管理器中的安装项目,突出显示添加,然后选择项目输出,添加 windows 服务和 windows 窗体输出,您将在安装项目下的解决方案资源管理器中看到它们。

  5. 添加 Windows 服务比这更进一步,但这也是另一个主题 google it

  6. 为 windows 应用程序创建快捷方式并将其添加到启动文件夹也是另一个主题 google 或与我联系。

    注意以关闭按钮不显示并且表单变为 Me.visible = false 的方式对表单进行编程,双击系统托盘中的图标是在任何时候设置 me.visible=true.that 的唯一方法计算机启动,您的 Windows 窗体应用程序也启动,并且可见性立即设置为 false 但由于它有一个带有图标图像的通知图标,它将显示在系统托盘中,双击它使表单可见以编辑您的设置正在存储服务,该服务也会自动启动,因为您会在设置项目中设置服务时设置它。我的邮件是 [email protected] 使用屏幕截图更好地说明并完整解释