我最近编写了一个小课程,帮助我更改Windows服务(我在某处找到的大多数代码)上的恢复选项。该代码为第一次,第二次和随后的失败创建一个FailureAction。每个Failure对象都包含一个类型(None,Restart,Reboot,RunCommand)和一个Delay(int)(以毫秒为单位)。这些对象打包在一个结构中并传递到ChangeServiceConfig2(WinAPI P/Invoke)中。但是,当我实际上右键单击控制台上的服务并转到“恢复”选项卡时,只能为所有失败(第一,第二和后续)设置延迟(“重新启动服务器之后”字段)一次。当我以编程方式设置它时,它会从第一个FailureAction开始延迟并忽略所有其他操作。有谁知道这是为什么?为什么只有第一个使用的时候,我们必须为所有的FailureAction对象传递延迟值?我误解了什么吗?在Windows服务上设置恢复选项
此外,设置dwResetPeriod /“重置失败计数后”似乎没有任何效果。
代码:
public class ServiceConfigurator
{
private const int SERVICE_ALL_ACCESS = 0xF01FF;
private const int SC_MANAGER_ALL_ACCESS = 0xF003F;
private const int SERVICE_CONFIG_DESCRIPTION = 0x1;
private const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2;
private const int SERVICE_NO_CHANGE = -1;
private const int ERROR_ACCESS_DENIED = 5;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct SERVICE_FAILURE_ACTIONS
{
public int dwResetPeriod;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpRebootMsg;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpCommand;
public int cActions;
public IntPtr lpsaActions;
}
[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")]
private static extern bool ChangeServiceFailureActions(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS lpInfo);
[DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")]
private static extern bool ChangeServiceDescription(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo);
[DllImport("kernel32.dll")]
private static extern int GetLastError();
private IntPtr _ServiceHandle;
public IntPtr ServiceHandle { get { return _ServiceHandle; } }
public ServiceConfigurator(ServiceController svcController)
{
this._ServiceHandle = svcController.ServiceHandle.DangerousGetHandle();
}
public void SetRecoveryOptions(FailureAction pFirstFailure, FailureAction pSecondFailure, FailureAction pSubsequentFailures, int pDaysToResetFailureCount = 0)
{
int NUM_ACTIONS = 3;
int[] arrActions = new int[NUM_ACTIONS * 2];
int index = 0;
arrActions[index++] = (int)pFirstFailure.Type;
arrActions[index++] = pFirstFailure.Delay;
arrActions[index++] = (int)pSecondFailure.Type;
arrActions[index++] = pSecondFailure.Delay;
arrActions[index++] = (int)pSubsequentFailures.Type;
arrActions[index++] = pSubsequentFailures.Delay;
IntPtr tmpBuff = Marshal.AllocHGlobal(NUM_ACTIONS * 8);
try
{
Marshal.Copy(arrActions, 0, tmpBuff, NUM_ACTIONS * 2);
SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS();
sfa.cActions = 3;
sfa.dwResetPeriod = pDaysToResetFailureCount;
sfa.lpCommand = null;
sfa.lpRebootMsg = null;
sfa.lpsaActions = new IntPtr(tmpBuff.ToInt32());
bool success = ChangeServiceFailureActions(_ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa);
if(!success)
{
if(GetLastError() == ERROR_ACCESS_DENIED)
throw new Exception("Access denied while setting failure actions.");
else
throw new Exception("Unknown error while setting failure actions.");
}
}
finally
{
Marshal.FreeHGlobal(tmpBuff);
tmpBuff = IntPtr.Zero;
}
}
}
特雷弗
要为什么只用了只有第一个我假设微软还没有实现的每个故障动作的差异延迟你的问题。尽管只使用第一个结构类型,但对每个结构类型使用一个结构类型可能更容易。此外,服务管理器窗口中的恢复选项卡只有一个条目用于“之后的重新启动服务”,因此它似乎像Windows目前只打算关注第一个。 HTH – Jose 2012-01-26 17:14:58
@threed,此代码缺少FailureAction的定义 – user626528 2014-09-03 07:15:34
@ user626528:恐怕我无法再访问代码(我现在与其他公司有联系)。但据我记忆,'FailureAction'类实质上就是你在示例代码中看到的,它是一个具有两个属性的类:'Type'和'Delay'。 – Trevor 2014-09-03 17:10:26