C# 从计划任务开始时,如何让流程监听WinEvents?

C# 从计划任务开始时,如何让流程监听WinEvents?,c#,windows,winapi,clickonce,interprocess,C#,Windows,Winapi,Clickonce,Interprocess,我有一个C#内置的ClickOnce应用程序。正如您所知,ClickOnce应用程序在设计上不能以管理权限运行。但是,如果您需要执行需要提升权限的功能,则可以将另一个任意EXE与ClickOnce应用程序打包在一起,并根据需要让应用程序调用该单独的EXE 当然,问题是,每次调用单独的应用程序时,它都会触发UAC提示,询问用户是否真的希望以提升的权限运行。这个特定的应用程序处于一个非常封闭的环境中,我可以确保始终希望运行提升的特权部分。然而,当呈现给普通用户时,UAC的提示有时看起来很可怕 所以为

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

当然,问题是,每次调用单独的应用程序时,它都会触发UAC提示,询问用户是否真的希望以提升的权限运行。这个特定的应用程序处于一个非常封闭的环境中,我可以确保始终希望运行提升的特权部分。然而,当呈现给普通用户时,UAC的提示有时看起来很可怕

所以为了缓解这种情况,我构建了我的EXE,它只触发一次,然后继续在后台运行并侦听。然后,我的主流程会根据需要触发各种WinEvent,我将它们放在AIA_开始(
0xA000
)和AIA_结束(
0xAFFF
)之间,因为它们是社区保留的事件

还和我在一起吗?到目前为止,我所描述的一切都非常有效。但是,它仍然要求用户在每次启动应用程序时按一次“是”以显示UAC提示。我意识到我可以做得更好

通过创建一个启动辅助EXE的Windows计划任务,我只需要在安装时在UAC提示符上单击Yes。之后,我将能够简单地触发计划任务,从而以提升的权限启动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文件创建它,以便将
disallowstartifonbatters
属性设置为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>

2015-03-20T11:10:15

这说明在不同会话中运行的进程不起作用,这并不会让我对此感到太有希望。

在principle对象中,使用以下元素:

 <LogonType>InteractiveToken</LogonType>
InteractiveToken

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

我们可以看到计划任务吗?@MatthewFrontino-添加了有关计划任务的信息。请按照您的原则尝试此操作:InteractiveToken IE:“仅在用户登录时运行”单选按钮。有一个无GUI模式任务可能会导致您丢失WinMessages。谷歌“windows绕过uipi”寻找更好的方法。@MatthewFrontino-太棒了!将LogonType更改为InteractiveToken(然后从我的create语句中删除/RU和/RP参数)效果非常好!如果你想提交答案,我会接受的。