简体   繁体   English

从 Windows 服务启动 GUI 应用程序 - 方法

[英]Starting GUI application from Windows Service - Approaches

Note: Despite appearing as yet another question of the same matter, it's not, but choosing the right title seems hard so more appropriate title change is welcome.注意:尽管出现了同一问题的另一个问题,但事实并非如此,但选择正确的标题似乎很难,因此欢迎更合适的标题更改。

I'm trying to solve an issue of starting up GUI application (Windows Forms, .NET) from a service application on Windows 7 Embedded (POS ready), and have come across several solutions, but none of them worked, with one exception I discovered along the way: Using a batch file as a helper file.我正在尝试解决从 Windows 7 Embedded(POS 就绪)上的服务应用程序启动 GUI 应用程序(Windows Forms,.NET)的问题,并且遇到了几种解决方案,但它们都没有工作,除了一个例外我一路上发现:使用批处理文件作为帮助文件。

Background: There are several posts like this describing why this has been removed and protected, and I understand session 0 isolation, but before any debate dives into why this shouldn't be done, I'm just trying to get my head around it, as I don't like the current solution that our company is using.背景:有几篇这样的帖子描述了为什么它已被删除和保护,我理解 session 0 隔离,但在任何辩论深入探讨为什么不应该这样做之前,我只是想弄清楚它,因为我不喜欢我们公司目前使用的解决方案。

I'll be using words "actual app" which represents two GUI applications that I've tried to run.我将使用“实际应用程序”一词,它代表我尝试运行的两个 GUI 应用程序。 One is Windows Forms .NET exe, and second Adobe AIR build exe app.一个是 Windows Forms .NET exe,第二个是 Adobe AIR build exe 应用程序。

I've successfully set up a test service and have done tests with two accounts:我已经成功设置了测试服务并使用两个帐户进行了测试:

  • Running a service under Local System account (with and without "Interact with desktop" option...)在本地系统帐户下运行服务(带有和不带有“与桌面交互”选项...)
  • Running a service under Administrator account -> This approach does not allow use of CreateProcessAsUser since its already in user session在管理员帐户下运行服务-> 这种方法不允许使用 CreateProcessAsUser,因为它已经在用户 session 中

Under Local System account, it works as expected, and I've successfully executed CreateProcessAsUser" command as shown here by murrayu and used his helper class implementation , but with no success. While actual app starts up in GUI under user account, it either doesnt start (AIR), or it has issues and erros, mostly with Access Denied exceptions present (.NET app).在本地系统帐户下,它按预期工作,我已经成功执行了 murrayu 显示的 CreateProcessAsUser" 命令,并使用了他的助手 class 实现,但没有成功。虽然实际应用程序在用户帐户下的 GUI 中启动,但它要么没有启动(AIR),或者它有问题和错误,主要是存在访问被拒绝异常(.NET 应用程序)。

Under Administrator account, the solution using CreateProcessAsUser does not work as mentioned, but using approach B (code at the end of post) , which works fine for one app starting another app, did not work.在管理员帐户下,使用 CreateProcessAsUser 的解决方案无法正常工作,但使用方法B(帖子末尾的代码) ,该方法适用于一个应用程序启动另一个应用程序,但无法正常工作。 There was no GUI present, as expected in a way.正如预期的那样,没有 GUI 存在。

Third try, solution included helper application that service would call, which then starts up the actual app.第三次尝试,解决方案包括服务将调用的帮助应用程序,然后启动实际应用程序。 Testing this using Local System account and CreateProcessAsUser, then calling approach B in the helper app, resulted in the same behaviour as in first test, where service invoked actual app.使用本地系统帐户和 CreateProcessAsUser 对此进行测试,然后在帮助应用程序中调用方法B ,结果与第一次测试中的行为相同,其中服务调用了实际应用程序。

Oddly enough, opening up Notepad.exe, cmd.exe, calc.exe using CreateProcessAsUser works just fine.奇怪的是,使用 CreateProcessAsUser 打开 Notepad.exe、cmd.exe、calc.exe 工作正常。

Since command line worked, I went down that rabbit hole: The fourth try, solution included a batch file, that included a single command:由于命令行工作,我去了那个兔子洞:第四次尝试,解决方案包括一个批处理文件,其中包括一个命令:

START D:\TESTAPP\DotNetApp.lnk

Note that it points to the shortcut, as calling exe directly does not work.请注意,它指向快捷方式,因为直接调用 exe 不起作用。

To my surprise, this approach worked!令我惊讶的是,这种方法奏效了! The actual app started as if started regularly by executing the file manually.实际的应用程序就像通过手动执行文件定期启动一样启动。

Now what bugs me the most is - Is there something I haven't found or try yet?现在最让我烦恼的是 - 有什么我还没有找到或尝试过的东西吗? Did I miss something important?我错过了什么重要的事情吗? The .NET app was ran using Administrator account with full rights when it reported Access denied exceptions, and works totaly fine even under User account (restricted) if executed manually form folder, so there's really nothing special about it that would seem like a cause of the errors when ran from service. .NET 应用程序在报告访问被拒绝异常时使用具有完全权限的管理员帐户运行,并且即使在用户帐户(受限)下如果手动执行表单文件夹也可以正常工作,因此它确实没有什么特别之处,这似乎是导致从服务运行时出错。

Most importantly, or most wondering question though: What does the command line / batch do that makes it work?最重要或最想知道的问题是:命令行/批处理是如何使它工作的? Is it possible to program it's behaviour / solution in a helper app, or better yet, directly in the service itself?是否可以在帮助应用程序中编程它的行为/解决方案,或者更好的是,直接在服务本身中编程?

Also, when wanting to have a service handle GUI application, and where relying on Startup/Autorun is not desirable, what would be the better solution?此外,当想要一个服务处理 GUI 应用程序,并且不希望依赖启动/自动运行时,更好的解决方案是什么?

Appendix B :附录B

public static void ElevatedExecute(string processName, string command, bool useAdminElevationRights = false)
        {
            Process process = new Process();
            process.StartInfo = new ProcessStartInfo(processName, command);
            if (useAdminElevationRights)
            {
                SecureString ssPwd = new SecureString();
                process.StartInfo.UserName = "Administrator";
                string tmpPass = ADMIN_PASSWORD;
                for (int x = 0; x < tmpPass.Length; x++)
                    ssPwd.AppendChar(tmpPass[x]);
                process.StartInfo.Password = ssPwd;
            }
            process.StartInfo.UseShellExecute = false;
            process.Start();
        }

Any insights would be highly appreciated.任何见解将不胜感激。

Is there a compelling reason to have the service start a UI app?是否有令人信服的理由让服务启动 UI 应用程序? I mean, since UI apps are meant for user interaction, how does the service know if a user is actually sitting down at the computer at any given time?我的意思是,由于 UI 应用程序是为用户交互而设计的,那么服务如何知道用户在任何给定时间是否真的坐在电脑前? What triggers the service to start the app?什么触发服务启动应用程序? If the user closes the app, what triggers the app to restart the UI?如果用户关闭应用程序,是什么触发应用程序重新启动 UI? Why can't the user just start the app directly?为什么用户不能直接启动应用程序? What is the service bringing to the table that the app can't do directly?应用程序无法直接完成的服务是什么?

We use a Windows service as part of our project.我们使用 Windows 服务作为我们项目的一部分。 It runs in the background 24/7/365.它在后台 24/7/365 运行。 It sits idle in steady-state until a user opens the UI application.它处于稳定状态,直到用户打开 UI 应用程序。 During the UI initialization, it establishes a connection to the service which it maintains until the UI is closed.在 UI 初始化期间,它会建立与它所维护的服务的连接,直到 UI 关闭。 As the user interacts with the UI, commands are sent to the service behind the scenes directing the service what to do.当用户与 UI 交互时,命令被发送到幕后的服务,指示服务做什么。

The point is, is there a reason why you can't have your service operate this way?关键是,您有什么理由不能让您的服务以这种方式运行? Instead of the service opening the app, let the user open the app when she's ready to, and then have the app connect to the service via IPC to facilitate any necessary UI-service interaction.与其让服务打开应用程序,不如让用户在准备好时打开应用程序,然后让应用程序通过 IPC 连接到服务以促进任何必要的 UI 服务交互。 You could even provide the feature to allow the app to collapse to the system tray, effectively hiding it until the user needs to access it again.您甚至可以提供允许应用折叠到系统托盘的功能,有效地将其隐藏,直到用户需要再次访问它。 Virus scan software works this way, and we've employed the approach in a version of our tool病毒扫描软件以这种方式工作,我们在我们的工具版本中采用了这种方法

HTH HTH

After some trial and error coding for a day now, I've managed to debug and figure out what was causing errors in solution with using pInvoke to CreateProcessAsUser() method in advapi32.dll module.经过一天的试错编码,我已经设法调试并找出导致解决方案错误的原因,方法是在advapi32.dll模块中使用 pInvoke 到CreateProcessAsUser()方法。

As stated in the question itself, theres a topic on how to invoke GUI process from session 0 to current's user session using CreateProcessAsUser() method.如问题本身所述, 有一个关于如何使用 CreateProcessAsUser() 方法从 session 0 到当前用户 session 调用 GUI 进程的主题

I've mistakenly ignored the working directory path to it, so some relative paths have not been working when GUI process was invoked, resulting in otherwise fully and nicely working implementation of StartProcessAsCurrentUser wrapper for CreateProcessAsUser() pInvoke.我错误地忽略了它的工作目录路径,因此在调用 GUI 进程时一些相对路径没有工作,导致CreateProcessAsUser() pInvoke 的StartProcessAsCurrentUser包装器的完全和很好的工作实现。

The correct call for an app example is:应用程序示例的正确调用是:

StartProcessAsCurrentUser(@"D:\Presentations\GUI.exe", null, @"D:\Presentations", true);

(where Presentations\GUI.exe is an example app. The null parameter is optional arguments parameter, and 3rd parameter is working directory, which I mistakenly always invoked as null. (其中 Presentations\GUI.exe 是一个示例应用程序。null 参数是可选的 arguments 参数,第三个参数是工作目录,我总是错误地将其调用为 null。

I figure it might be helpful to leave this here, since there really aren't that many topics about invoking GUI application from service or session 0, or even remotely using ManagementClass instance method InvokeMethod("Create", {0});我认为把它留在这里可能会有所帮助,因为关于从服务或 session 0 调用 GUI 应用程序,甚至远程使用ManagementClass instance method InvokeMethod("Create", {0});的主题并不多。 on a remote host, which works pretty much the same way.在远程主机上,其工作方式几乎相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM