作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试 P/调用 NotifyServiceStatusChange event在 C# 中检查服务何时停止。我设法让它编译和运行没有任何错误,但现在,当我停止服务时,它似乎不想通知它已死。任何想法为什么会这样?您可以通过将此代码复制到一个空白的控制台应用程序中来对其进行测试;请务必将“我的服务名称”替换为您的服务名称(下面有两个此字符串的实例)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
public delegate void StatusChanged(IntPtr parameter);
public class SERVICE_NOTIFY : MarshalByRefObject
{
public uint dwVersion;
public StatusChanged pfnNotifyCallback;
public IntPtr pContext;
public uint dwNotificationStatus;
public SERVICE_STATUS_PROCESS ServiceStatus;
public uint dwNotificationTriggered;
public IntPtr pszServiceNames;
};
public struct SERVICE_STATUS_PROCESS {
public uint dwServiceType;
public uint dwCurrentState;
public uint dwControlsAccepted;
public uint dwWin32ExitCode;
public uint dwServiceSpecificExitCode;
public uint dwCheckPoint;
public uint dwWaitHint;
public uint dwProcessId;
public uint dwServiceFlags;
};
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern uint NotifyServiceStatusChange(IntPtr hService, uint dwNotifyMask, ref IntPtr pNotifyBuffer);
public static SERVICE_NOTIFY notify;
public static GCHandle notifyHandle;
public static IntPtr unmanagedNotifyStructure;
static void Main(string[] args)
{
IntPtr hSCM = OpenSCManager(null, null, (uint)0xF003F);
if (hSCM != IntPtr.Zero)
{
IntPtr hService = OpenService(hSCM, "My Service Name", (uint)0xF003F);
if (hService != IntPtr.Zero)
{
StatusChanged changeDelegate = ReceivedStatusChangedEvent;
notify = new SERVICE_NOTIFY();
notify.dwVersion = 2;
notify.pfnNotifyCallback = changeDelegate;
notify.pContext = IntPtr.Zero;
notify.dwNotificationStatus = 0;
SERVICE_STATUS_PROCESS process;
process.dwServiceType = 0;
process.dwCurrentState = 0;
process.dwControlsAccepted = 0;
process.dwWin32ExitCode = 0;
process.dwServiceSpecificExitCode = 0;
process.dwCheckPoint = 0;
process.dwWaitHint = 0;
process.dwProcessId = 0;
process.dwServiceFlags = 0;
notify.ServiceStatus = process;
notify.dwNotificationTriggered = 0;
notify.pszServiceNames = Marshal.StringToHGlobalUni("My Service Name");
notifyHandle = GCHandle.Alloc(notify);
unmanagedNotifyStructure = Marshal.AllocHGlobal((IntPtr)(notifyHandle));
NotifyServiceStatusChange(hService, (uint)0x00000001, ref unmanagedNotifyStructure);
Console.WriteLine("Waiting for the service to stop. Press enter to exit.");
Console.ReadLine();
}
}
}
public static void ReceivedStatusChangedEvent(IntPtr parameter)
{
Console.WriteLine("Service stopped.");
}
}
}
最佳答案
如果你想保留你目前正在尝试的功能,你将需要多线程。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public class SERVICE_NOTIFY
{
public uint dwVersion;
public IntPtr pfnNotifyCallback;
public IntPtr pContext;
public uint dwNotificationStatus;
public SERVICE_STATUS_PROCESS ServiceStatus;
public uint dwNotificationTriggered;
public IntPtr pszServiceNames;
};
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SERVICE_STATUS_PROCESS
{
public uint dwServiceType;
public uint dwCurrentState;
public uint dwControlsAccepted;
public uint dwWin32ExitCode;
public uint dwServiceSpecificExitCode;
public uint dwCheckPoint;
public uint dwWaitHint;
public uint dwProcessId;
public uint dwServiceFlags;
};
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern uint NotifyServiceStatusChange(IntPtr hService, uint dwNotifyMask, IntPtr pNotifyBuffer);
[DllImportAttribute("kernel32.dll", EntryPoint = "SleepEx")]
public static extern uint SleepEx(uint dwMilliseconds, [MarshalAsAttribute(UnmanagedType.Bool)] bool bAlertable);
public static SERVICE_NOTIFY notify;
public static GCHandle notifyHandle;
public static IntPtr unmanagedNotifyStructure;
static void Main(string[] args)
{
IntPtr hSCM = OpenSCManager(null, null, (uint)0xF003F);
if (hSCM != IntPtr.Zero)
{
IntPtr hService = OpenService(hSCM, "Apache2.2", (uint)0xF003F);
if (hService != IntPtr.Zero)
{
StatusChanged changeDelegate = ReceivedStatusChangedEvent;
notify = new SERVICE_NOTIFY();
notify.dwVersion = 2;
notify.pfnNotifyCallback = Marshal.GetFunctionPointerForDelegate(changeDelegate);
notify.pContext = IntPtr.Zero;
notify.dwNotificationStatus = 0;
SERVICE_STATUS_PROCESS process;
process.dwServiceType = 0;
process.dwCurrentState = 0;
process.dwControlsAccepted = 0;
process.dwWin32ExitCode = 0;
process.dwServiceSpecificExitCode = 0;
process.dwCheckPoint = 0;
process.dwWaitHint = 0;
process.dwProcessId = 0;
process.dwServiceFlags = 0;
notify.ServiceStatus = process;
notify.dwNotificationTriggered = 0;
notify.pszServiceNames = Marshal.StringToHGlobalUni("Apache2.2");
notifyHandle = GCHandle.Alloc(notify, GCHandleType.Pinned);
unmanagedNotifyStructure = notifyHandle.AddrOfPinnedObject();
NotifyServiceStatusChange(hService, (uint)0x00000001, unmanagedNotifyStructure);
GC.KeepAlive(changeDelegate);
Console.WriteLine("Waiting for the service to stop. Press enter to exit.");
while (true)
{
try
{
string keyIn = Reader.ReadLine(500);
break;
}
catch (TimeoutException)
{
SleepEx(100,true);
}
}
notifyHandle.Free();
}
}
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void StatusChanged(IntPtr parameter);
public static void ReceivedStatusChangedEvent(IntPtr parameter)
{
Console.WriteLine("Service stopped.");
}
}
}
class Reader
{
private static Thread inputThread;
private static AutoResetEvent getInput, gotInput;
private static string input;
static Reader()
{
inputThread = new Thread(reader);
inputThread.IsBackground = true;
inputThread.Start();
getInput = new AutoResetEvent(false);
gotInput = new AutoResetEvent(false);
}
private static void reader()
{
while (true)
{
getInput.WaitOne();
input = Console.ReadLine();
gotInput.Set();
}
}
public static string ReadLine(int timeOutMillisecs)
{
getInput.Set();
bool success = gotInput.WaitOne(timeOutMillisecs);
if (success)
return input;
else
throw new TimeoutException("User did not provide input within the timelimit.");
}
}
关于c# - 为什么我的解决方案不适用于 C# 中的 P/Invoke NotifyServiceStatusChange?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20061459/
我是一名优秀的程序员,十分优秀!