繁体   English   中英

从计划任务启动时,如何使进程监听WinEvents?

[英]How can I get my process listening for WinEvents when started from a Scheduled Task?

我有一个用C#内置的ClickOnce应用程序。 如您所知,按设计,ClickOnce应用程序无法以管理特权运行。 但是,如果您需要执行需要提升特权的功能,则可以做的是将另一个任意EXE与ClickOnce应用程序一起打包,并根据需要让应用程序调用该单独的EXE。

当然,问题在于,每次您调用单独的应用程序时,都会触发UAC提示,询问用户是否确实要使用提升的特权运行。 这个特定的应用程序处于非常封闭的环境中,我可以确保我始终希望运行特权提升部分。 但是,将其呈现给普通用户时,有时该UAC提示似乎令人恐惧。

因此,为了减轻这种情况,我以仅触发一次的方式构建了EXE,然后继续在后台运行并侦听WinEvents 然后,我的主进程会根据需要触发各种WinEvent,并将它们放在AIA_START( 0xA000 )和AIA_END( 0xAFFF )之间,因为它们是社区保留的事件。

还在我这儿? 到目前为止,我所描述的已经非常完美。 但是,它仍然需要用户在每次启动应用程序时按一次“是”到UAC提示符。 我意识到我可以做得更好。

通过创建触发我的辅助EXE的Windows计划任务,安装后,我只需要在UAC提示符下单击“是”即可。 之后,我将仅能够触发“计划任务”,从而以提升的特权启动EXE。 而且这似乎也起作用。 我可以验证我的EXE是否以管理权限启动,并且每次都有效地绕过了UAC提示,这很棒。

但是 ,既然我是从计划任务中启动EXE而不是直接启动它,则似乎不再需要监听在ClickOnce应用程序中触发的WinEvents。 或者,如果正在侦听(我想是),那么交流中会遇到障碍。 我不太确定是什么阻碍了事情,因为看起来两个进程仍在Windows中的同一用户帐户下运行。

有谁知道为什么我的辅助进程通过计划任务启动后似乎不再响应WinEvents? 我该如何解决呢? 我意识到我可以使用不同的通信线路(在TCP端口上监听,在共享文件上连续轮询等),但是由于我已经编写了发送和侦听WinEvents的代码,因此我更希望继续使用那。

如果您好奇的话,下面是我用来监听WinEvents的代码的简要概述:

public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);

private void App_OnStartup(object sender, StartupEventArgs e)
{
    var handler = new WinEventDelegate(MyHandlerMethod);
    SetWinEventHook(0xA000, 0xAFFF, IntPtr.Zero, handler, 0, 0, 0x0002);
}

private void MyHandlerMethod(IntPtr hook, uint evt, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
    // handle the incoming WinEvents here
}

根据要求,这是我要创建计划任务的工作。 我必须使用XML文件创建它,以便可以将DisallowStartIfOnBatteries属性设置为false。 因此,使用以下XML文件...

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2015-03-20T11:10:15</Date>
    <Author>myuser</Author>
  </RegistrationInfo>
  <Triggers>
    <TimeTrigger>
      <StartBoundary>2014-01-01T00:00:00</StartBoundary>
      <Enabled>true</Enabled>
    </TimeTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>myuser</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\MySecondaryApp.exe</Command>
    </Exec>
  </Actions>
</Task>

...我调用schtasks.exe /Create /TN MySecondaryApp /XML task.xml /RU myuser /RP mypassword创建任务。 此操作确实需要用户在UAC提示符下按“是”,但是显然创建是一次操作,这意味着我可以在安装过程中自行完成。 从那时起,我要做的就是调用schtasks.exe /Run /TN MySecondaryApp启动该过程。 因为已经在任务上设置了“以最高特权运行”属性,所以这无需任何其他UAC提示。

就像我说的那样,我已经验证了这可行。 以这种方式运行时,WinEvents侦听器似乎不起作用。 我只是碰到另一个SO问题 ,它说在不同的会话中运行的进程在WinEvents中是行不通的,这不会使我对此抱有太大希望。

在您的主要对象中,使用以下元素:

 <LogonType>InteractiveToken</LogonType>

添加此XML标记会将计划的任务更改为“仅在用户登录时运行”选项,这与完整的GUI模式相关,在该模式下您将再次看到Windows消息。

暂无
暂无

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

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