![](/img/trans.png)
[英]how can i find the instanceid/correlation ID of the scheduled Task that started my process
[英]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.