从 Windows 服务启动 GUI 应用程序 - 方法 [英] Starting GUI application from Windows Service - Approaches

查看:236
本文介绍了从 Windows 服务启动 GUI 应用程序 - 方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:尽管似乎是同一问题的另一个问题,但事实并非如此,但选择正确的标题似乎很难,因此欢迎更改更合适的标题.

我正在尝试解决从 Windows 7 Embedded(POS 就绪)上的服务应用程序启动 GUI 应用程序(Windows 窗体、.NET)的问题,并且遇到了多种解决方案,但它们都不起作用,一路上我发现了一个例外:使用批处理文件作为帮助文件.

背景:有几个帖子像 this 描述了为什么它已被删除和保护,我理解会话 0 隔离,但在讨论为什么不应该这样做之前,我只是想弄清楚围绕它,因为我不喜欢我们公司当前使用的解决方案.

我将使用实际应用程序"这个词,它代表我尝试运行的两个 GUI 应用程序.一个是 Windows Forms .NET exe,第二个是 Adob​​e AIR build exe 应用程序.

我已经成功设置了一个测试服务,并且已经使用两个帐户进行了测试:

  • 在本地系统帐户下运行服务(使用和不使用与桌面交互"选项...)
  • 在管理员帐户下运行服务 -> 这种方法不允许使用 CreateProcessAsUser,因为它已经在用户会话中

在本地系统帐户下,它按预期工作,并且我已成功执行 CreateProcessAsUser" 命令,如图所示 这里来自 murrayu 并使用了他的助手类实现,但没有成功.虽然实际应用程序在用户帐户下在 GUI 中启动,它要么无法启动 (AIR),要么存在问题和错误,主要是存在拒绝访问异常(.NET 应用程序).

在管理员帐户下,使用 CreateProcessAsUser 的解决方案不像前面提到的那样工作,但使用方法 B(文章末尾的代码),这对一个应用程序工作正常启动另一个应用程序,没有用.在某种程度上,正如预期的那样,没有 GUI.

第三次尝试,解决方案包括服务将调用的辅助应用程序,然后启动实际的应用程序.使用本地系统帐户和 CreateProcessAsUser 对此进行测试,然后在帮助应用程序中调用方法 B,导致与第一次测试相同的行为,其中服务调用实际应用程序.>

奇怪的是,使用 CreateProcessAsUser 打开 Notepad.exe、cmd.exe、calc.exe 工作正常.

由于命令行有效,我进入了那个兔子洞:第四次尝试,解决方案包含一个批处理文件,其中包含一个命令:

开始 D:\TESTAPP\DotNetApp.lnk

注意它指向快捷方式,因为直接调用exe不起作用.

令我惊讶的是,这种方法奏效了!实际的应用程序就像通过手动执行文件定期启动一样.

现在最让我烦恼的是 - 有什么我还没有找到或尝试过的吗?我错过了什么重要的事情吗?.NET 应用程序在报告访问被拒绝的异常时使用具有完全权限的管理员帐户运行,并且如果手动执行表单文件夹,即使在用户帐户(受限)下也能正常工作,所以它真的没有什么特别之处,这似乎是一个原因从服务运行时的错误.

最重要的,或者说是最令人疑惑的问题:命令行/批处理做了什么让它工作?是否可以在辅助应用程序中编写其行为/解决方案,或者直接在服务本身中编写更好的程序?

此外,当想要一个服务处理 GUI 应用程序,并且不希望依赖启动/自动运行时,什么是更好的解决方案?

附录B:

public static void ElevatedExecute(string processName, string command, bool useAdminElevationRights = false){进程进程=新进程();process.StartInfo = new ProcessStartInfo(processName, command);如果(使用AdminElevationRights){SecureString ssPwd = new SecureString();process.StartInfo.UserName = "管理员";字符串 tmpPass = ADMIN_PASSWORD;for (int x = 0; x 

任何见解将不胜感激.

解决方案

经过一天的尝试和错误编码,我已经设法调试并找出导致解决方案中使用 pInvoke 的错误的原因 CreateProcessAsUser() 方法在 advapi32.dll 模块中.

如问题本身所述,有一个关于如何使用 CreateProcessAsUser() 方法将 GUI 进程从会话 0 调用到当前用户会话的主题.

我错误地忽略了它的工作目录路径,所以在调用 GUI 进程时一些相对路径没有工作,导致 StartProcessAsCurrentUser 包装器的 StartProcessAsCurrentUser 以其他方式完全和良好地工作实现>CreateProcessAsUser() pInvoke.

应用示例的正确调用是:

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

(其中 Presentations\GUI.exe 是一个示例应用程序.空参数是可选参数参数,第三个参数是工作目录,我错误地总是将其调用为空.

我认为把它留在这里可能会有所帮助,因为关于从服务或会话 0 调用 GUI 应用程序,甚至远程使用 ManagementClass 实例方法 InvokeMethod("Create", {0});在远程主机上,其工作方式几乎相同.

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.

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.

I'll be using words "actual app" which represents two GUI applications that I've tried to run. One is Windows Forms .NET exe, and second Adobe AIR build exe app.

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

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).

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. There was no GUI present, as expected in a way.

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.

Oddly enough, opening up Notepad.exe, cmd.exe, calc.exe using CreateProcessAsUser works just fine.

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.

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.

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?

Appendix 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.

解决方案

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.

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.

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.

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.

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});on a remote host, which works pretty much the same way.

这篇关于从 Windows 服务启动 GUI 应用程序 - 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆