mirror of https://github.com/dahall/Vanara.git
Fixed NotifyServiceStatusChange code and unit test
parent
fb62105f42
commit
692524a94a
|
@ -82,9 +82,9 @@ namespace Vanara.PInvoke
|
|||
|
||||
/// <summary>Callback function used in <see cref="SERVICE_NOTIFY_2"/> to alert changes registered by <see cref="NotifyServiceStatusChange"/>.</summary>
|
||||
/// <param name="pParameter">A pointer to the SERVICE_NOTIFY structure provided by the caller.</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
[PInvokeData("winsvc.h", MSDNShortId = "52ede72e-eb50-48e2-b5c1-125816f6fe57")]
|
||||
public delegate void PFN_SC_NOTIFY_CALLBACK(ref SERVICE_NOTIFY_2 pParameter);
|
||||
public delegate void PFN_SC_NOTIFY_CALLBACK(in SERVICE_NOTIFY_2 pParameter);
|
||||
|
||||
/// <summary>
|
||||
/// <para>The entry point for a service.</para>
|
||||
|
@ -2696,7 +2696,7 @@ namespace Vanara.PInvoke
|
|||
// SC_HANDLE hService, DWORD dwNotifyMask, PSERVICE_NOTIFYA pNotifyBuffer );
|
||||
[DllImport(Lib.AdvApi32, SetLastError = false, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("winsvc.h", MSDNShortId = "e22b7f69-f096-486f-97fa-0465bef499cd")]
|
||||
public static extern Win32Error NotifyServiceStatusChange(SC_HANDLE hService, SERVICE_NOTIFY_FLAGS dwNotifyMask, ref SERVICE_NOTIFY_2 pNotifyBuffer);
|
||||
public static extern Win32Error NotifyServiceStatusChange(SC_HANDLE hService, SERVICE_NOTIFY_FLAGS dwNotifyMask, in SERVICE_NOTIFY_2 pNotifyBuffer);
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
|
@ -4795,8 +4795,7 @@ namespace Vanara.PInvoke
|
|||
/// </para>
|
||||
/// <para>If this member is valid, the notification callback function must free the string using the LocalFree function.</para>
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string pszServiceNames;
|
||||
public StrPtrAuto pszServiceNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -4957,7 +4956,7 @@ namespace Vanara.PInvoke
|
|||
// dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD
|
||||
// dwCheckPoint; DWORD dwWaitHint; } SERVICE_STATUS, *LPSERVICE_STATUS;
|
||||
[PInvokeData("winsvc.h", MSDNShortId = "d268609b-d442-4d0f-9d49-ed23fee84961")]
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SERVICE_STATUS
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -5480,7 +5479,7 @@ namespace Vanara.PInvoke
|
|||
/// is running and on normal termination.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public uint dwWin32ExitCode;
|
||||
public Win32Error dwWin32ExitCode;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using static Vanara.PInvoke.AdvApi32;
|
||||
|
@ -20,9 +19,9 @@ namespace Vanara.PInvoke.Tests
|
|||
public void _Setup()
|
||||
{
|
||||
hSvcMgr = OpenSCManager(null, null, ScManagerAccessTypes.SC_MANAGER_ALL_ACCESS);
|
||||
AssertHandleIsValid(hSvcMgr);
|
||||
Assert.That(hSvcMgr, ResultIs.ValidHandle);
|
||||
hSvc = OpenService(hSvcMgr, svcName, ServiceAccessTypes.SERVICE_ALL_ACCESS);
|
||||
AssertHandleIsValid(hSvc);
|
||||
Assert.That(hSvc, ResultIs.ValidHandle);
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
|
@ -83,53 +82,49 @@ namespace Vanara.PInvoke.Tests
|
|||
{
|
||||
var sb = new StringBuilder(1024, 1024);
|
||||
var sz = (uint)sb.Capacity;
|
||||
var ret = GetServiceKeyName(hSvcMgr, svcKey, sb, ref sz);
|
||||
TestContext.WriteLine(ret ? sb.ToString() : $"Error: {Win32Error.GetLastError()}");
|
||||
Assert.That(ret, Is.True);
|
||||
Assert.That(GetServiceKeyName(hSvcMgr, svcKey, sb, ref sz), ResultIs.Successful);
|
||||
TestContext.WriteLine(sb);
|
||||
Assert.That(sb.ToString(), Is.EqualTo(svcName));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NotifyServiceStatusChangeTest()
|
||||
{
|
||||
var cnt = 0;
|
||||
Thread.BeginThreadAffinity();
|
||||
var callback = new PFN_SC_NOTIFY_CALLBACK(ChangeDelegate);
|
||||
GC.KeepAlive(callback);
|
||||
var svcNotify = new SERVICE_NOTIFY_2
|
||||
{
|
||||
dwVersion = 2,
|
||||
pfnNotifyCallback = ChangeDelegate
|
||||
pfnNotifyCallback = callback
|
||||
};
|
||||
Thread.BeginThreadAffinity();
|
||||
var ret = NotifyServiceStatusChange(hSvc, SERVICE_NOTIFY_FLAGS.SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_FLAGS.SERVICE_NOTIFY_PAUSE_PENDING | SERVICE_NOTIFY_FLAGS.SERVICE_NOTIFY_CONTINUE_PENDING, ref svcNotify);
|
||||
if (ret.Failed) TestContext.WriteLine(ret);
|
||||
Assert.That(ret.Succeeded, Is.True);
|
||||
new Thread(ThreadExec).Start();
|
||||
Kernel32.SleepEx(10000, true);
|
||||
GC.KeepAlive(svcNotify);
|
||||
Assert.That(NotifyServiceStatusChange(hSvc, SERVICE_NOTIFY_FLAGS.SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_FLAGS.SERVICE_NOTIFY_PAUSE_PENDING | SERVICE_NOTIFY_FLAGS.SERVICE_NOTIFY_CONTINUE_PENDING, svcNotify), ResultIs.Successful);
|
||||
var th = new Thread(ThreadExec);
|
||||
th.Start((SC_HANDLE)hSvc);
|
||||
while (th.IsAlive)
|
||||
Kernel32.SleepEx(100, true);
|
||||
Thread.EndThreadAffinity();
|
||||
Assert.That(cnt, Is.EqualTo(3));
|
||||
|
||||
void ChangeDelegate(ref SERVICE_NOTIFY_2 pParameter)
|
||||
void ChangeDelegate(in SERVICE_NOTIFY_2 pParameter)
|
||||
{
|
||||
TestContext.WriteLine(pParameter.ServiceStatus.dwCurrentState);
|
||||
cnt++;
|
||||
System.Diagnostics.Debug.WriteLine(pParameter.ServiceStatus.dwCurrentState);
|
||||
}
|
||||
|
||||
void ThreadExec()
|
||||
void ThreadExec(object handle)
|
||||
{
|
||||
using (var mgr = OpenSCManager(null, null, ScManagerAccessTypes.SC_MANAGER_ALL_ACCESS))
|
||||
{
|
||||
if (!mgr.IsInvalid)
|
||||
{
|
||||
using (var svc = OpenService(hSvcMgr, svcName, ServiceAccessTypes.SERVICE_ALL_ACCESS))
|
||||
{
|
||||
if (!svc.IsInvalid)
|
||||
{
|
||||
TestContext.WriteLine("Pausing...");
|
||||
ControlService(svc, ServiceControl.SERVICE_CONTROL_PAUSE, out _);
|
||||
Thread.Sleep(3000);
|
||||
TestContext.WriteLine("Continuing...");
|
||||
ControlService(svc, ServiceControl.SERVICE_CONTROL_CONTINUE, out _);
|
||||
Thread.Sleep(3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var svc = (SC_HANDLE)handle;
|
||||
System.Diagnostics.Debug.WriteLine("Pausing...");
|
||||
if (!ControlService(svc, ServiceControl.SERVICE_CONTROL_PAUSE, out _))
|
||||
System.Diagnostics.Debug.WriteLine($"Pausing failed: {Win32Error.GetLastError()}");
|
||||
WaitForServiceStatus(svc, ServiceState.SERVICE_PAUSED);
|
||||
System.Diagnostics.Debug.WriteLine("Continuing...");
|
||||
if (!ControlService(svc, ServiceControl.SERVICE_CONTROL_CONTINUE, out _))
|
||||
System.Diagnostics.Debug.WriteLine($"Pausing failed: {Win32Error.GetLastError()}");
|
||||
WaitForServiceStatus(svc, ServiceState.SERVICE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +133,7 @@ namespace Vanara.PInvoke.Tests
|
|||
{
|
||||
using (var scm = OpenSCManager(null, null, ScManagerAccessTypes.SC_MANAGER_CONNECT))
|
||||
{
|
||||
AssertHandleIsValid(scm);
|
||||
Assert.That(scm, ResultIs.ValidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,19 +143,10 @@ namespace Vanara.PInvoke.Tests
|
|||
//opens task scheduler service
|
||||
using (var service = OpenService(hSvcMgr, "Schedule", ServiceAccessTypes.SERVICE_QUERY_STATUS))
|
||||
{
|
||||
AssertHandleIsValid(service);
|
||||
Assert.That(service, ResultIs.ValidHandle);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void QueryServiceStatusTest()
|
||||
{
|
||||
//query service status
|
||||
var ret = QueryServiceStatus(hSvc, out var i);
|
||||
TestContext.WriteLine(ret ? i.dwCurrentState.ToString() : $"Error: {Win32Error.GetLastError()}");
|
||||
Assert.That(ret, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void QueryServiceStatusExTest()
|
||||
{
|
||||
|
@ -171,6 +157,15 @@ namespace Vanara.PInvoke.Tests
|
|||
Assert.That(status.dwServiceFlags, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void QueryServiceStatusTest()
|
||||
{
|
||||
//query service status
|
||||
var ret = QueryServiceStatus(hSvc, out var i);
|
||||
TestContext.WriteLine(ret ? i.dwCurrentState.ToString() : $"Error: {Win32Error.GetLastError()}");
|
||||
Assert.That(ret, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StartStopServiceTest()
|
||||
{
|
||||
|
@ -199,19 +194,9 @@ namespace Vanara.PInvoke.Tests
|
|||
}
|
||||
}
|
||||
|
||||
private static void AssertHandleIsValid(SafeSC_HANDLE handle)
|
||||
{
|
||||
if (handle.IsInvalid)
|
||||
Win32Error.ThrowLastError();
|
||||
|
||||
Assert.That(handle.IsNull, Is.False);
|
||||
Assert.That(handle.IsClosed, Is.False);
|
||||
Assert.That(handle.IsInvalid, Is.False);
|
||||
}
|
||||
|
||||
private static ServiceState GetState(SC_HANDLE handle) => QueryServiceStatus(handle, out var i) ? i.dwCurrentState : throw Win32Error.GetLastError().GetException();
|
||||
|
||||
private static void WaitForServiceStatus(SafeSC_HANDLE service, ServiceState status)
|
||||
private static void WaitForServiceStatus(SC_HANDLE service, ServiceState status)
|
||||
{
|
||||
//query service status again to check that it changed
|
||||
var tests = 0;
|
||||
|
|
Loading…
Reference in New Issue