none
AdjustTokenPrivilegesでシャットダウン時にエラー RRS feed

  • 質問

  • 初投稿です。

    私自身、経験も浅く至らない点もあると思いますがよろしくお願いします。

    現在VisualStudio2005のVB.NETで、指定された時間になったら自動でWindowsを終了させる機能を作成しています。OSはWindowsXP SP2を使用しております。

    様々なサイトを参考に作ってみたのですが、デバッグで指定時間にモジュールから関数を呼び出してこの処理を通ると「PInvoke シグネチャがアンマネージ ターゲット シグネチャに一致していないことが原因として考えられます。呼び出し規約、および PInvoke シグネチャのパラメータがターゲットのアンマネージ シグネチャに一致していることを確認してください。」というエラーが表示されますが、処理を続行するとそのままシャットダウンができます。

    EXEで起動すればエラーも表示されずにシャットダウン出来るのですが、このエラーについて調べ、AdjustTokenPrivilegesを宣言時の修飾子が違っていることが分かったので、正しい修飾子に直して実行した場合、エラーは出なくなりましたがAdjustTokenPrivilegesの処理がどうやってもFalseになってしまい、シャットダウン処理(ExitWindowsEx)まで行けなくなってしまいました。引数がおかしいのか何なのか…

    この件に関して何か分かる方がおりましたらご教授をお願いします。

    以下、エラーが出るけどシャットダウンは出来るソースです。


    Option Explicit On 

    Imports System.Runtime.InteropServices

    '構造体宣言
    <StructLayout(LayoutKind.Sequential)> _
    Public Structure LUID   'ローカル一意識別子
        Public lowpart As Integer
        Public highpart As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure TOKEN_PRIVILEGES   'トークン特権
        Public PrivilegeCount As Integer
        Public TheLuid As LUID
        Public Attributes As Integer
    End Structure

    'プロトタイプ宣言
    Public Class Win32
        '現在のプロセスに対応する疑似ハンドルを取得する
        Declare Function GetCurrentProcess Lib "kernel32" () As IntPtr
        'プロセスに関連付けられているアクセストークンを開く
        Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As IntPtr, _
            ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
        '指定されたシステムで使われているローカル一意識別子(LUID)を取得し、指定された特権名をローカルで表現する
        Declare Function LookupPrivilegeValue Lib "advapi32.dll" Alias "LookupPrivilegeValueA" ( _
            ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
        '指定したアクセストークン内の特権を有効または無効にする
        Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As IntPtr, _
            ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, _
            ByVal BufferLength As Integer, ByVal PreviousState As TOKEN_PRIVILEGES, _
            ByVal ReturnLength As IntPtr) As Boolean
        ''PreviousStateはByRefが正しいが、処理がFalseになってしまうためByValを使用
        'Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As IntPtr, _
        '    ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, _
        '    ByVal BufferLength As Integer, ByRef PreviousState As TOKEN_PRIVILEGES, _
        '    ByVal ReturnLength As IntPtr) As Boolean
        '現在のユーザーをログオフさせるorシステムをシャットダウンorシャットダウン+再起動させる
        Declare Function ExitWindowsEx Lib "user32.dll" (ByVal uFlags As Int32, _
            ByVal dwReserved As Int32) As Int32
    End Class

    Module Shutdown
        
    '定数宣言
        '特権
        Public Const SE_SHUTDOWN_NAME = "SeShutdownPrivilege"

        '特権属性
        Public Const SE_PRIVILEGE_ENABLED As Integer = &H2

        'OSの種類
        Public Const VER_PLATFORM_WIN32s As Long = 0&           'WINDOWS3.1
        Public Const VER_PLATFORM_WIN32_WINDOWS As Long = 1&    'WINDOWS9x
        Public Const VER_PLATFORM_WIN32_NT As Long = 2&         'WINDOWSNT,2000 XP

        'アクセス権
        Public Const TOKEN_QUERY As Integer = &H8
        Public Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20

        'Windows終了フラグ(win32s API)
        Public Const EWX_LOGOFF As Integer = &H0    '現在のユーザーのログオフ
        Public Const EWX_SHUTDOWN As Integer = &H1  'システムをシャットダウンし、電源を切っても良い状態にする
        Public Const EWX_REBOOT As Integer = &H2    'システムをシャットダウンし、システムの再起動をする
        Public Const EWX_FORCE As Integer = &H4     'プロセスの強制終了

        'Windows終了フラグ
        Public Const WINDOW_LOGOFF As Integer = 1
        Public Const WINDOW_REBOOT As Integer = 2
        Public Const WINDOW_SHUTDOWN As Integer = 3
        Public Const WINDOW_FORCE_LOGOFF As Integer = 11
        Public Const WINDOW_FORCE_REBOOT As Integer = 12
        Public Const WINDOW_FORCE_SHUTDOWN As Integer = 13

        '---------------------------------------------------------------
        '機能   指定時間になったら呼び出してWindowsを終了させる
        '引数   Sw      1:ログオフ      2:リブート      3:シャットダウン
        '              11:強制ログオフ 12:強制リブート 13:強制シャットダウン
        '戻値   成功:0  失敗:0以外
        '---------------------------------------------------------------
        Public Function shutdown(ByVal Sw As Integer) As Integer
            Dim tkp As TOKEN_PRIVILEGES
            Dim tkp2 As TOKEN_PRIVILEGES
            Dim tmpLuid As LUID
            Dim handle As IntPtr = IntPtr.Zero
            Dim cmd As Integer
            Dim Result As Boolean
            Dim Ret As Integer

            Select Case Sw
                Case WINDOW_LOGOFF : cmd = EWX_LOGOFF                       'ログオフ
                Case WINDOW_REBOOT : cmd = EWX_REBOOT                       'リブート
                Case WINDOW_SHUTDOWN : cmd = EWX_SHUTDOWN                   'シャットダウン
                Case WINDOW_FORCE_LOGOFF : cmd = EWX_FORCE + EWX_LOGOFF     '強制ログオフ
                Case WINDOW_FORCE_REBOOT : cmd = EWX_FORCE + EWX_REBOOT     '強制リブート
                Case WINDOW_FORCE_SHUTDOWN : cmd = EWX_FORCE + EWX_SHUTDOWN '強制シャットダウン
            End Select

            Ret = 0
            Select Case Sw
                Case WINDOW_LOGOFF, WINDOW_FORCE_LOGOFF
                    Result = Win32.ExitWindowsEx(cmd, 0)    '終了処理実行
                    If Result = 0 Then Ret = 1

                Case WINDOW_REBOOT, WINDOW_SHUTDOWN, WINDOW_FORCE_REBOOT, WINDOW_FORCE_SHUTDOWN
                    If CreateObject("SYSINFO.Sysinfo").OSPlatform() = VER_PLATFORM_WIN32_NT Then
                        'OSの種類がWindowsNT/2000/XPの場合、以下の処理を行う
                        'プロセスに関連づけアクセストークンのオープン
                        Result = Win32.OpenProcessToken(Win32.GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, handle)
                        If Result <> 0 Then
                            'ローカルシステムのシャットダウン特権の取得
                            Result = Win32.LookupPrivilegeValue(vbNullString, SE_SHUTDOWN_NAME, tmpLuid)
                            If Result <> 0 Then
                                tkp.PrivilegeCount = 1
                                tkp.TheLuid = tmpLuid
                                tkp.Attributes = SE_PRIVILEGE_ENABLED

                                'アクセストークンの特権を変更する
                                Result = Win32.AdjustTokenPrivileges(handle, False, tkp, Len(tkp2), tkp2, IntPtr.Zero)
                                '※PreviousStateの修飾子が本来のものと違うためエラー(本来のByRefを使うとどうしてもFalseになる)

                                If Result <> 0 Then
                                    Result = Win32.ExitWindowsEx(cmd, 0)    '終了処理実行
                                    If Result = 0 Then Ret = 5
                                Else
                                    Ret = 4
                                End If
                            Else
                                Ret = 3
                            End If
                        Else
                            Ret = 2
                        End If
                    Else
                        Result = Win32.ExitWindowsEx(cmd, 0)    '終了処理実行
                        If Result = 0 Then Ret = 5
                    End If
                Case Else
                    Ret = 9
            End Select

            shutdown = Ret
        End Function

    End Module


    2006年11月21日 0:46

すべての返信

  • お世話になります。

    AdjustTokenPrivilegesの宣言部分等を変更するとうまく動くようです。

    <宣言>
    Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As IntPtr, _
            ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, _
            ByVal BufferLength As Integer, ByVal PreviousState As IntPtr, _
            ByVal ReturnLength As IntPtr) As Boolean


    <呼出>
    Result = Win32.AdjustTokenPrivileges(handle, False, tkp, Len(tkp2), IntPtr.Zero, IntPtr.Zero)

    最後の引数にNULLが入る場合、その1つ前の引数にもNULLを入れる必要があるようです。調べたサイトと宣言の型は違うのですが、エラーも出ないのでこれでいこうと思います。

    いろいろ調べてくださった方、ありがとうございました。

    2006年12月7日 4:55