none
Windows XP SP3 で ExitWindowsEx が失敗する RRS feed

  • 質問

  • いつもお世話になっております。

    Windows XP SP3 にしてから ExitWindowsEx 関数が失敗する現象が出ました。

    環境:Windows XP SP3、ワークグループ環境
    準備:外部からコマンドを受け付けて処理をおこなう(自作)サービスが登録されている。

    Windows XP SP3 でコンピュータに一度ログオンしてからログオフした状態にします。
    この状態で、Ctrl+Alt+Deleteを押下して、アカウントを入力する画面にします。

    上記状態のコンピュータに ExitWindowsEx を使用してシャットダウンするように命令を発行します。
    ※ 命令を受けて実行するのは、準備に記述した自作サービス。
    引数は、ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0)です。
    ※ 引数を変えて試しましたが、引数には影響しないようです。

    XP SP3 以外の XP や他のOSではシャットダウンがおこなわれるのですが、
    XP SP3 では、失敗します。GetLastError は、ERROR_ALREADY_EXISTS です。

    ワークグループではなく、ドメイン環境の場合は成功します。
    コンピュータを起動してから、一度もログオンしなければ成功します。

    この現象についてなにかわかるかたいらっしゃいますでしょうか?

    ちなみに XP SP3 では、別件の不具合を修正するため、
    ExitWindowsEx と winlogon.exe に修正がはいっているようです。


    よろしくお願いします。


    2008年7月24日 10:41

回答

すべての返信

  • 同環境 XP SP3 ドメイン環境で試しています
    ログインしている状態では、電源OFFは行われます。

    ログイン画面では電源OFFされません。

            EventLog.WriteEntry(SOURCE_NAME, "シャットダウンのメッセージを受け取りました。", EventLogEntryType.Information);
            AdjustToken();
            EventLog.WriteEntry(SOURCE_NAME, "シャットダウン特権を取得しました。", EventLogEntryType.Information);
            bool ret = ExitWindowsEx(ExitWindows.EWX_POWEROFF | ExitWindows.EWX_FORCE, 0);
            EventLog.WriteEntry(SOURCE_NAME, "シャットダウンの指示が完了しました。-" + ret + "-" + Marshal.GetLastWin32Error(), EventLogEntryType.Information);

    各メッセージは正常
    サービス自体には渡っている様子ですが、実際に電源OFFしない。

            public void AdjustToken()
            {
                const uint TOKEN_ADJUST_PRIVILEGES = 0x20;
                const uint TOKEN_QUERY = 0x8;
                const int SE_PRIVILEGE_ENABLED = 0x2;
                const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";

                if (Environment.OSVersion.Platform != PlatformID.Win32NT)
                    return;

                IntPtr procHandle = GetCurrentProcess();

                //トークンを取得する
                IntPtr tokenHandle;
                if (true == OpenProcessToken(procHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out tokenHandle))
                {
                    EventLog.WriteEntry(SOURCE_NAME, "○トークンを取得成功 " + Marshal.GetLastWin32Error(), EventLogEntryType.Information);
                }
                else
                {
                    EventLog.WriteEntry(SOURCE_NAME, "×トークンを取得失敗 " + Marshal.GetLastWin32Error(), EventLogEntryType.Information);
                }

                //LUIDを取得する
                TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES();
                tp.Attributes = SE_PRIVILEGE_ENABLED;
                tp.PrivilegeCount = 1;
                if (true == LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, out tp.Luid))
                {
                    EventLog.WriteEntry(SOURCE_NAME, "○LUIDを取得成功 " + Marshal.GetLastWin32Error(), EventLogEntryType.Information);
                }
                else
                {
                    EventLog.WriteEntry(SOURCE_NAME, "×LUIDを取得失敗 " + Marshal.GetLastWin32Error(), EventLogEntryType.Information);
                }

                //特権を有効にする
                if (true == AdjustTokenPrivileges(tokenHandle, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
                {
                    EventLog.WriteEntry(SOURCE_NAME, "○特権を有効を取得成功 " + Marshal.GetLastWin32Error(), EventLogEntryType.Information);
                }
                else
                {
                    EventLog.WriteEntry(SOURCE_NAME, "×特権を有効を取得失敗 " + Marshal.GetLastWin32Error(), EventLogEntryType.Information);
                }
            }


    トークンについても、全て正常。

    何故かログイン画面では無視される
    だれか原因をご存じないでしょうか?

    2010年2月9日 7:17
  • 自己解決

    サービスのアカウントをローカルアカウントにすれば解決しました。
    • 回答としてマーク 菊地俊介 2010年2月23日 5:01
    2010年2月9日 9:13
  • 今後のためということで書いておきます。

    元の質問は、1 年半前という古いものです。
    関連性があるかもしれませんが、さすがにこれだけ古いスレッドで類似質問をされると、話の流れが読めません。

    今後は、関連する質問と思われるスレッドの URL を一緒に添えて、新しい質問をされると良いと思います。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年2月9日 14:12
    モデレータ