如何使用C#从Windows服务运行EXE程序?

如何使用C#从Windows服务运行EXE程序?

这是我的代码:

 System.Diagnostics.Process.Start(@"E:\PROJECT XL\INI SQLLOADER\ConsoleApplication2\ConsoleApplication2\ConsoleApplication2\bin\Debug\ConsoleApplication2.exe"); 

当我运行这个服务时,应用程序没有启动。
我的代码有什么问题?

这将永远不会工作 ,至少不在Windows Vista或更高版本。 关键的问题是,你试图从一个Windows服务,而不是一个标准的Windows应用程序执行此操作。 您所展示的代码可以在Windows窗体,WPF或控制台应用程序中正常工作,但在Windows服务中完全不起作用。

Windows服务无法启动其他应用程序,因为它们不在任何特定用户的上下文中运行。 与常规Windows应用程序不同, 服务现在在隔离的会话中运行,并禁止与用户或桌面进行交互。 这不会让应用程序运行。

这些相关问题的答案中有更多信息:

  • 当一个Timer事件引发时,Windows服务如何启动一个进程?
  • 在Windows中哪个进程是用户特定的?
  • Windows服务(允许服务与桌面交互)

正如您现在可能已经想出的那样,您的问题的最佳解决方案是创建一个标准的Windows应用程序而不是服务。 这些被设计为由特定用户运行并且与该用户的桌面相关联。 这样,您可以使用您已经显示的代码随时运行其他应用程序。

假设您的控制台应用程序不需要任何接口或输出,另一种可能的解决方案是指示进程不要创建一个窗口。 这将阻止Windows阻止您的进程创建,因为它不会再要求创建控制台窗口。 您可以在相关问题的答案中找到相关的代码。

首先,我们要创建一个在System帐户下运行的Windows服务。 此服务将负责在当前活动的用户会话中产生一个交互式进程。 这个新创建的进程将显示一个用户界面,并运行完整的管理权限。 当第一个用户登录到计算机时,此服务将启动并将在Session0中运行; 但是此服务产生的进程将在当前登录的用户的桌面上运行。 我们将把这个服务称为LoaderService。

接下来,winlogon.exe进程负责管理用户登录和注销过程。 我们知道,每个登录到计算机的用户都将拥有唯一的会话ID和与其会话关联的相应winlogon.exe进程。 现在,我们在上面提到,LoaderService在System帐户下运行。 我们还确认,计算机上的每个winlogon.exe进程都在系统帐户下运行。 因为系统帐户是LoaderService和winlogon.exe进程的所有者,所以我们的LoaderService可以复制winlogon.exe进程的访问令牌(和会话ID),然后调用Win32 API函数CreateProcessAsUser来启动进程当前活动会话的登录用户。 由于位于复制的winlogon.exe进程的访问令牌中的会话ID大于0,我们可以使用该令牌启动交互式进程。

试试这个。 在32位和64位体系结构中颠覆Vista UAC

我已经试过这篇文章代码项目 ,它对我来说工作得很好。 我也使用了代码。 文章用截图很好的解释。

我正在为这种情况添加必要的解释

您刚启动电脑,即将登录。 登录时,系统会为您分配一个唯一的会话ID。 在Windows Vista中,第一个登录到计算机的用户被OS分配了一个会话ID。 下一个要登录的用户将被分配一个会话ID 2.等等等等。 您可以从任务管理器中的用户选项卡查看分配给每个登录用户的会话ID。 在这里输入图像说明

但是,您的Windows服务被带到了会话ID为0.该会话与其他会话隔离。 这最终会阻止Windows服务调用在用户会话(如1或2)下运行的应用程序。

为了从Windows服务调用应用程序,您需要从作为当前登录用户的winlogon.exe复制控件,如下图所示。 在这里输入图像说明

重要的代码

 // obtain the process id of the winlogon process that // is running within the currently active session Process[] processes = Process.GetProcessesByName("winlogon"); foreach (Process p in processes) { if ((uint)p.SessionId == dwSessionId) { winlogonPid = (uint)p.Id; } } // obtain a handle to the winlogon process hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); // obtain a handle to the access token of the winlogon process if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) { CloseHandle(hProcess); return false; } // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser // I would prefer to not have to use a security attribute variable and to just // simply pass null and inherit (by default) the security attributes // of the existing token. However, in C# structures are value types and therefore // cannot be assigned the null value. SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.Length = Marshal.SizeOf(sa); // copy the access token of the winlogon process; // the newly created token will be a primary token if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) { CloseHandle(hProcess); CloseHandle(hPToken); return false; } STARTUPINFO si = new STARTUPINFO(); si.cb = (int)Marshal.SizeOf(si); // interactive window station parameter; basically this indicates // that the process created can display a GUI on the desktop si.lpDesktop = @"winsta0\default"; // flags that specify the priority and creation method of the process int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // create a new process in the current User's logon session bool result = CreateProcessAsUser(hUserTokenDup, // client's access token null, // file to execute applicationName, // command line ref sa, // pointer to process SECURITY_ATTRIBUTES ref sa, // pointer to thread SECURITY_ATTRIBUTES false, // handles are not inheritable dwCreationFlags, // creation flags IntPtr.Zero, // pointer to new environment block null, // name of current directory ref si, // pointer to STARTUPINFO structure out procInfo // receives information about new process ); 

在Windows XP中,您可以很好地从Windows服务执行.exe。 我以前是自己做的。

您需要确保在Windows服务属性中选中了“允许与桌面交互”选项。 如果没有完成,它将不会执行。

我需要检查在Windows 7或Vista,因为这些版本需要额外的安全权限,所以它可能会引发错误,但我很确定它可以直接或间接地实现。 对XP来说,我确信自己已经做到了。

我想你是复制.exe到不同的位置。 这可能是我想的问题。 当你复制exe时,你不会复制它的依赖关系。

所以,你可以做的是,把所有依赖的DLL在GAC中,以便任何.net exe可以访问它

否则,不要将exe复制到新位置。 只需创建一个环境变量,并在您的C#中调用该exe文件。 由于路径是在环境变量中定义的,exe文件可以被你的c#程序访问。

更新:

以前我在我的c#.net 3.5项目中有一种类似的问题,我试图从c#.net代码运行.exe文件,该exe文件只是另一个项目exe文件(我添加了几个支持dll的我的功能)和我在我的EXE应用程序中使用的DLL的方法。 最后我解决了这个问题,把这个应用程序作为一个单独的项目创建到同一个解决方案中,并且把项目输出添加到我的部署项目中 根据这个情景,我回答说,如果不是他想要的,那我非常抱歉。

System.Diagnostics.Process.Start(“Exe Name”);