【问题标题】:Windows will not shutdown programmatically when logged off注销时 Windows 不会以编程方式关闭
【发布时间】:2009-05-14 14:52:49
【问题描述】:

我有一个使用本地管理员帐户从服务中启动的应用程序。此应用程序可通过网络浏览器访问,主机PC可通过此界面关闭。

如果用户登录到主机 PC 并且我浏览到它并关闭它,应用程序将退出并按照我的预期关闭 PC - 使用 ExitWindowsEx()(启用关闭权限)。

但是,如果 PC 已注销,我浏览到它 - 应用程序仍在服务中运行,并尝试使用 ExitWindowsEx() 关闭,它返回成功并且似乎没有问题,但 PC 永远不会关闭下来。

我也尝试过 InitiateSystemShutdown() ,它奇怪地失败并返回错误 2! (该系统找不到指定的文件)。

我使用什么帐户来启动应用程序似乎并不重要。

任何帮助将不胜感激!

谢谢。

【问题讨论】:

  • 这不是很好的帮助,但是,既然你说“任何帮助”:你能从服务而不是应用程序调用 ExitWindowsEx 吗?
  • 也试过了,还是没关机!甚至检查了事件日志并且关闭请求没有像往常一样在那里注册,所以没有线索!?

标签: windows windows-services shutdown


【解决方案1】:

很遗憾,无法复制。我有一个预先存在的服务,它公开了一个邮槽,所以我添加了代码:

void RebootThisMachine ()
{
   if (GrabPrivilege (SE_SHUTDOWN_NAME))
   {
      if (!InitiateSystemShutdown (NULL,NULL,0,TRUE,TRUE))
      {
         wsprintf (g_szDebug, TEXT("RebootMachine - ISS failed, error %d"),
                   GetLastError()) ;
         DebugMessage (DEBUG_ERROR, g_szDebug) ;
      }
   }
   else
   {
      wsprintf (g_szDebug, TEXT("RebootMachine - cannot grab priv, error %d"),
                GetLastError()) ;
      DebugMessage (DEBUG_ERROR, g_szDebug) ;
   }
}

当我收到来自我编写的一个小命令行实用程序的邮槽消息时调用它。 InitiateSystemShutdown 是服务的正确 API,无论是否登录,它都会重新启动运行该服务的机器。如果我的(vista)机器没有登录,关机确实需要一段时间,但它最终会起作用(在说“关机”的 30-40 秒之后)。我的服务在 LocalSystem 下执行。 GrabPrivilege 与我之前发布的代码相同。

因此,您可以放心,您正在尝试做的事情可能的。我看到您正在使用管理员帐户来运行您的服务。您是否尝试过在 LocalSystem 下运行服务以进行关机测试?也许您的管理员的权限与 LocalSystem 的权限不太匹配...

【讨论】:

  • 感谢您的帮助,我会再试一次,看看我是否还有运气。
【解决方案2】:

如果我是http://www.google.ca/search?hl=en&q=exitwindowsex+service,那么我首先找到的是http://www.eggheadcafe.com/software/aspnet/29901267/lockworkstation-and-exitw.aspx,这表明如果您的服务启用了“与桌面交互”标志(已弃用),则会出现问题。

然后人们会在回复上述主题的各种消息中提出修复建议,例如http://www.eggheadcafe.com/conversation.aspx?messageid=29901274&threadid=29901267 ...类似的内容可能会对您有所帮助。

另一种选择,当然是一个杂项,但避免使用建议的魔法,可能是运行第二个不与桌面交互的服务:让第二个服务调用 ExitWindowsEx ...并使用任何 IPC (或特定于服务的 API)从第一个服务(或可能来自应用程序)触发第二个服务。

【讨论】:

    【解决方案3】:

    试试这段代码,告诉我们它的作用:

    GrabPrivilege (SE_SHUTDOWN_NAME);
    ExitWindowsEx (EWX_REBOOT|EWX_FORCE, 0); // or whatever EWX flags you want
    

    辅助函数:

    BOOL  GrabPrivilege (LPCTSTR lpctPrivName) 
    {
       TOKEN_PRIVILEGES newtkp;
       HANDLE hToken;
       BOOL   bRetVal = FALSE;
    
       if (OpenProcessToken (GetCurrentProcess(), 
                             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
                             &hToken)) 
       {
          LookupPrivilegeValue (NULL, 
                                lpctPrivName, 
                                &newtkp.Privileges[0].Luid); 
          newtkp.PrivilegeCount = 1;  // one privilege to set
          newtkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
    
          if (AdjustTokenPrivileges (hToken, 
                                     FALSE, 
                                     &newtkp, 
                                     0, 
                                     (PTOKEN_PRIVILEGES) NULL, 
                                     0))
          {
             DWORD dwRet = GetLastError();
             if (dwRet == ERROR_SUCCESS) bRetVal = TRUE;
          }
       }
       CloseHandle (hToken);
       return bRetVal;
    }
    

    【讨论】:

    • 感谢您的建议,不幸的是,这与我目前使用的代码完全相同,但不起作用!
    • 糟糕,这就是我没有仔细阅读问题所得到的结果。最常见的问题是没有启用关闭权限。发生了一个想法 - SE_SHUTDOWN_NAME 假设一个登录会话,但在您的失败案例中没有一个。您是否尝试过启用 SE_REMOTE_SHUTDOWN_NAME ?
    • 嗯,是的,我会试一试,看看有什么不同
    • 不幸的是,这似乎也没有效果,仍然从 ExitWindowsEx() 调用返回成功,但什么也没发生。
    • 评论太长,添加了另一个答案。
    【解决方案4】:

    您是否尝试过使用 shutdown.exe 工具?它报告什么错误?

    我在使用 Windows XP x64 时遇到了同样的问题,但我是通过 WMI 远程执行的,但关机工具给了我同样的错误 (21)。有了这些信息,我发现了这个修补程序:

    http://support.microsoft.com/kb/834100

    我无法测试它,因为我手头没有 Windows 2003 Server,但也许它有帮助。

    【讨论】:

      猜你喜欢
      • 2012-06-15
      • 2019-01-02
      • 2015-06-19
      • 2015-07-22
      • 2011-03-07
      • 2012-01-10
      • 2012-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多