Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ServiceController.Stop()之后服务未完全停止_C#_.net_Sql Server_Service - Fatal编程技术网

C# ServiceController.Stop()之后服务未完全停止

C# ServiceController.Stop()之后服务未完全停止,c#,.net,sql-server,service,C#,.net,Sql Server,Service,SomeService在sqlserver文件上工作。DoSomething()要复制该SQL文件。如果某个服务未完全关闭,它将抛出一个错误,因为数据库文件仍处于锁定状态。在前面提到的代码中,我通过了WaitForStopped()方法,但是服务直到DoSomething()之后才释放数据库文件,因此我得到了一个错误 做更多的调查,我发现在DoSomething方法调用之前,我看到服务控制器的状态显示为stopped,但查看一些ProcMon日志,服务会在我从DoSomething抛出错误后释放

SomeService在sqlserver文件上工作。DoSomething()要复制该SQL文件。如果某个服务未完全关闭,它将抛出一个错误,因为数据库文件仍处于锁定状态。在前面提到的代码中,我通过了WaitForStopped()方法,但是服务直到DoSomething()之后才释放数据库文件,因此我得到了一个错误

做更多的调查,我发现在DoSomething方法调用之前,我看到服务控制器的状态显示为stopped,但查看一些ProcMon日志,服务会在我从DoSomething抛出错误后释放数据库文件

另外,如果我在WaitForStopped和DoSomething方法之间放置一个线程,比如说。。。5秒后,数据库文件被释放,一切正常。然而,这不是我正在寻找的担保方案


有什么想法吗?

尝试使用环境。退出(1)

当我停止了一个依赖于另一个服务的服务,而第二个服务持有我甚至不知道它正在使用的资源时,我就看到了这一点。你认为可能是这样吗?我知道SQL有很多不同的组件,但我还没有研究是否有多个与之相关的服务


祝你好运

ServiceController.WaitForStopped()/WaitForStatus()将在服务实现声明其已停止后返回。这并不意味着进程已经释放了所有资源并退出。我见过SQL Server以外的数据库也这样做


如果您真的想确保数据库完全停止,您必须与数据库本身交互,获取进程id并等待其退出,等待释放文件上的锁,…

Windows服务是进程之上的一层;为了成为服务,应用程序必须连接到服务控制管理器并宣布哪些服务可用。此连接在ADVAPI32.DLL库中处理。一旦建立了此连接,库将维护一个线程,等待来自服务控制管理器的命令,然后服务控制管理器可以任意启动和停止服务。我认为当进程中的最后一个服务终止时,不需要退出该进程。虽然这是通常发生的情况,但在最后一个服务进入“停止”状态之后,与服务控制管理器的链接的结束可能会在流程实际终止之前发生,释放它尚未显式释放的任何资源

Windows服务API包含的功能允许您获取承载服务的进程的进程ID。单个进程可以承载多个服务,因此当您感兴趣的服务终止时,该进程可能不会实际退出,但使用SQL Server应该是安全的。不幸的是,.NET Framework没有公开此功能。但是,它确实将句柄公开给它内部用于API调用的服务,并且您可以使用它来进行自己的API调用。然后,通过一点P/Invoke,您可以获得Windows服务进程的进程ID,并且从那里,如果您具有必要的权限,您可以打开进程的句柄,该句柄可用于等待它退出

大概是这样的:

ServiceController serviceController = new ServiceController(someService);
serviceController.Stop();
serviceController.WaitForStopped();
DoSomething();

就我而言,我使用了interops:

[DllImport("advapi32")]
static extern bool QueryServiceStatusEx(IntPtr hService, int InfoLevel, ref SERVICE_STATUS_PROCESS lpBuffer, int cbBufSize, out int pcbBytesNeeded);

const int SC_STATUS_PROCESS_INFO = 0;

[StructLayout(LayoutKind.Sequential)]
struct SERVICE_STATUS_PROCESS
{
  public int dwServiceType;
  public int dwCurrentState;
  public int dwControlsAccepted;
  public int dwWin32ExitCode;
  public int dwServiceSpecificExitCode;
  public int dwCheckPoint;
  public int dwWaitHint;
  public int dwProcessId;
  public int dwServiceFlags;
}

const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;

const int SERVICE_RUNS_IN_SYSTEM_PROCESS = 0x00000001;

public static void StopServiceAndWaitForExit(string serviceName)
{
  using (ServiceController controller = new ServiceController(serviceName))
  {
    SERVICE_STATUS_PROCESS ssp = new SERVICE_STATUS_PROCESS();
    int ignored;

    // Obtain information about the service, and specifically its hosting process,
    // from the Service Control Manager.
    if (!QueryServiceStatusEx(controller.ServiceHandle.DangerousGetHandle(), SC_STATUS_PROCESS_INFO, ref ssp, Marshal.SizeOf(ssp), out ignored))
      throw new Exception("Couldn't obtain service process information.");

    // A few quick sanity checks that what the caller wants is *possible*.
    if (ssp.dwServiceType != SERVICE_WIN32_OWN_PROCESS)
      throw new Exception("Can't wait for the service's hosting process to exit because there may be multiple services in the process (dwServiceType is not SERVICE_WIN32_OWN_PROCESS");

    if ((ssp.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS) != 0)
      throw new Exception("Can't wait for the service's hosting process to exit because the hosting process is a critical system process that will not exit (SERVICE_RUNS_IN_SYSTEM_PROCESS flag set)");

    if (ssp.dwProcessId == 0)
      throw new Exception("Can't wait for the service's hosting process to exit because the process ID is not known.");

    // Note: It is possible for the next line to throw an ArgumentException if the
    // Service Control Manager's information is out-of-date (e.g. due to the process
    // having *just* been terminated in Task Manager) and the process does not really
    // exist. This is a race condition. The exception is the desirable result in this
    // case.
    using (Process process = Process.GetProcessById(ssp.dwProcessId))
    {
      // EDIT: There is no need for waiting in a separate thread, because MSDN says "The handles are valid until closed, even after the process or thread they represent has been terminated." ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms684868%28v=vs.85%29.aspx ), so to keep things in the same thread, the process HANDLE should be opened from the process id before the service is stopped, and the Wait should be done after that.

      // Response to EDIT: What you report is true, but the problem is that the handle isn't actually opened by Process.GetProcessById. It's only opened within the .WaitForExit method, which won't return until the wait is complete. Thus, if we try the wait on the current therad, we can't actually do anything until it's done, and if we defer the check until after the process has completed, it won't be possible to obtain a handle to it any more.

      // The actual wait, using process.WaitForExit, opens a handle with the SYNCHRONIZE
      // permission only and closes the handle before returning. As long as that handle
      // is open, the process can be monitored for termination, but if the process exits
      // before the handle is opened, it is no longer possible to open a handle to the
      // original process and, worse, though it exists only as a technicality, there is
      // a race condition in that another process could pop up with the same process ID.
      // As such, we definitely want the handle to be opened before we ask the service
      // to close, but since the handle's lifetime is only that of the call to WaitForExit
      // and while WaitForExit is blocking the thread we can't make calls into the SCM,
      // it would appear to be necessary to perform the wait on a separate thread.
      ProcessWaitForExitData threadData = new ProcessWaitForExitData();

      threadData.Process = process;

      Thread processWaitForExitThread = new Thread(ProcessWaitForExitThreadProc);

      processWaitForExitThread.IsBackground = Thread.CurrentThread.IsBackground;
      processWaitForExitThread.Start(threadData);

      // Now we ask the service to exit.
      controller.Stop();

      // Instead of waiting until the *service* is in the "stopped" state, here we
      // wait for its hosting process to go away. Of course, it's really that other
      // thread waiting for the process to go away, and then we wait for the thread
      // to go away.
      lock (threadData.Sync)
        while (!threadData.HasExited)
          Monitor.Wait(threadData.Sync);
    }
  }
}

class ProcessWaitForExitData
{
  public Process Process;
  public volatile bool HasExited;
  public object Sync = new object();
}

static void ProcessWaitForExitThreadProc(object state)
{
  ProcessWaitForExitData threadData = (ProcessWaitForExitData)state;

  try
  {
    threadData.Process.WaitForExit();
  }
  catch {}
  finally
  {
    lock (threadData.Sync)
    {
      threadData.HasExited = true;
      Monitor.PulseAll(threadData.Sync);
    }
  }
}
[StructLayout(LayoutKind.Sequential)]
公共结构SC_句柄__
{
未使用的公共int;
}
[旗帜]
公共枚举服务\u控制:uint
{
停止=0x00000001,
暂停=0x00000002,
CONTINUE=0x00000003,
询问=0x00000004,
关机=0x00000005,
PARAMCHANGE=0x00000006,
NETBINDADD=0x00000007,
NETBINDREMOVE=0x00000008,
NETBINDENABLE=0x00000009,
NETBINDDISABLE=0x0000000A,
DEVICEEVENT=0x0000000B,
硬件配置更改=0x0000000C,
POWEREVENT=0x0000000D,
SESSIONCHANGE=0x0000000E
}
[StructLayout(LayoutKind.Sequential)]
公共结构服务\u状态
{
///DWORD->无符号整数
公共uint dwServiceType;
///DWORD->无符号整数
国家公共部门;
///DWORD->无符号整数
接受公共单位;
///DWORD->无符号整数
公共uint dwWin32ExitCode;
///DWORD->无符号整数
公共uint dwServiceSpecificExitCode;
///DWORD->无符号整数
公共交通检查站;
///DWORD->无符号整数
公共uint dwWaitHint;
}
公共类本地方法
{
公用工程内部SC\U管理器\u所有访问权限=(需要标准权限)
|(SC_管理器_连接)
|(SC_经理_创建_服务)
|(SC_经理_枚举_服务)
|(SC_经理_锁
|(SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG(())(SC_MANAGER_MODIFY_BOOT_CONFIG)()40;
///标准权限要求->(0x000F0000L)
公共建筑国际标准要求的权利=983040;
///SC_管理器_连接->0x0001
公共const int SC_MANAGER_CONNECT=1;
///SC_管理器_创建_服务->0x0002
公共const int SC_MANAGER_CREATE_SERVICE=2;
///SC_管理器_枚举_服务->0x0004
公共建筑内部管理人员枚举服务=4;
///SC_管理器_锁->0x0008
公共建筑内部管理器锁=8;
///SC_管理器_查询_锁定_状态->0x0010
公共const int SC_MANAGER_QUERY_LOCK_STATUS=16;
///SC\U管理器\u修改\u引导\u配置->0x0020
public const int SC_MANAGER_MODIFY_BOOT_CONFIG=32;
///服务控制停止->0x00000001
公用工程内部服务、控制和停止=1;
///服务查询状态->0x0004
公共const int SERVICE\u QUERY\u STATUS=4;
public const int GENERIC_EXECUTE=536870912;
///服务\u正在运行->0x00000004
公共const int SERVICE_RUNNING=4;
[DllImport(“advapi32.dll”,SetLastError=true,CharSet=CharSet.Auto)]
静态外部IntPtr OpenService(IntPtr hSCManager,字符串lpServiceName,uint DWR)
[StructLayout(LayoutKind.Sequential)]
public struct SC_HANDLE__
{
    public int unused;
}

[Flags]
public enum SERVICE_CONTROL : uint
{
    STOP = 0x00000001,
    PAUSE = 0x00000002,
    CONTINUE = 0x00000003,
    INTERROGATE = 0x00000004,
    SHUTDOWN = 0x00000005,
    PARAMCHANGE = 0x00000006,
    NETBINDADD = 0x00000007,
    NETBINDREMOVE = 0x00000008,
    NETBINDENABLE = 0x00000009,
    NETBINDDISABLE = 0x0000000A,
    DEVICEEVENT = 0x0000000B,
    HARDWAREPROFILECHANGE = 0x0000000C,
    POWEREVENT = 0x0000000D,
    SESSIONCHANGE = 0x0000000E
}

[StructLayout(LayoutKind.Sequential)]
public struct SERVICE_STATUS
{

    /// DWORD->unsigned int
    public uint dwServiceType;
    /// DWORD->unsigned int
    public uint dwCurrentState;
    /// DWORD->unsigned int
    public uint dwControlsAccepted;
    /// DWORD->unsigned int
    public uint dwWin32ExitCode;
    /// DWORD->unsigned int
    public uint dwServiceSpecificExitCode;
    /// DWORD->unsigned int
    public uint dwCheckPoint;
    /// DWORD->unsigned int
    public uint dwWaitHint;
}

public class NativeMethods
{
    public const int SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED
                | (SC_MANAGER_CONNECT
                | (SC_MANAGER_CREATE_SERVICE
                | (SC_MANAGER_ENUMERATE_SERVICE
                | (SC_MANAGER_LOCK
                | (SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG))))));

    /// STANDARD_RIGHTS_REQUIRED -> (0x000F0000L)
    public const int STANDARD_RIGHTS_REQUIRED = 983040;
    /// SC_MANAGER_CONNECT -> 0x0001
    public const int SC_MANAGER_CONNECT = 1;
    /// SC_MANAGER_CREATE_SERVICE -> 0x0002
    public const int SC_MANAGER_CREATE_SERVICE = 2;
    /// SC_MANAGER_ENUMERATE_SERVICE -> 0x0004
    public const int SC_MANAGER_ENUMERATE_SERVICE = 4;
    /// SC_MANAGER_LOCK -> 0x0008
    public const int SC_MANAGER_LOCK = 8;
    /// SC_MANAGER_QUERY_LOCK_STATUS -> 0x0010
    public const int SC_MANAGER_QUERY_LOCK_STATUS = 16;
    /// SC_MANAGER_MODIFY_BOOT_CONFIG -> 0x0020
    public const int SC_MANAGER_MODIFY_BOOT_CONFIG = 32;
    /// SERVICE_CONTROL_STOP -> 0x00000001
    public const int SERVICE_CONTROL_STOP = 1;
    /// SERVICE_QUERY_STATUS -> 0x0004
    public const int SERVICE_QUERY_STATUS = 4;
    public const int GENERIC_EXECUTE = 536870912;
    /// SERVICE_RUNNING -> 0x00000004
    public const int SERVICE_RUNNING = 4;

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

    [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW")]
    public static extern IntPtr OpenSCManagerW(
        [In()] [MarshalAs(UnmanagedType.LPWStr)] string lpMachineName,
        [In()] [MarshalAs(UnmanagedType.LPWStr)] string lpDatabaseName,
        uint dwDesiredAccess);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CloseServiceHandle(IntPtr hSCObject);

    [DllImport("advapi32.dll", EntryPoint = "QueryServiceStatus", CharSet = CharSet.Auto)]
    public static extern bool QueryServiceStatus(IntPtr hService, ref SERVICE_STATUS dwServiceStatus);

    [SecurityCritical]
    [HandleProcessCorruptedStateExceptions]
    public static void ServiceStop()
    {
        IntPtr manager = IntPtr.Zero;
        IntPtr service = IntPtr.Zero;
        SERVICE_STATUS status = new SERVICE_STATUS();

        if ((manager = OpenSCManagerW(null, null, SC_MANAGER_ALL_ACCESS)) != IntPtr.Zero)
        {
            if ((service = OpenService(manager, Resources.ServiceName, SC_MANAGER_ALL_ACCESS)) != IntPtr.Zero)
            {
                QueryServiceStatus(service, ref status);
            }

            if (status.dwCurrentState == SERVICE_RUNNING)
            {
                int i = 0;
                //not the best way, but WaitStatus didnt work correctly. 
                while (i++ < 10 && status.dwCurrentState != SERVICE_CONTROL_STOP)
                {
                    ControlService(service, SERVICE_CONTROL.STOP, ref status);
                    QueryServiceStatus(service, ref status);
                    Thread.Sleep(200);
                }

            }
        }


        if (manager != IntPtr.Zero)
        {
            var b = CloseServiceHandle(manager);
        }

        if (service != IntPtr.Zero)
        {
            var b = CloseServiceHandle(service);
        }
    }
}