管理者権限のアプリケーションから、他のアプリケーションを呼び出すと、呼ばれた側のアプリケーションのプロセスも管理者権限になります。
たまに、管理者権限だとうまく動作しないOCXなどがあるので、子プロセスを通常ユーザーの権限で起動させたい場合があります。
間にバッチファイルを噛ませてやってみましたが、管理者権限で起動してしまうのでダメでした。
スポンサーリンク
以下のページのソースコードを利用して、テストアプリを作ってみました。
https://social.msdn.microsoft.com/Forums/vstudio/en-US/3c9aa0fa-c860-4a26-bde0-4ccf8a3793b3/use-processstart-to-start-an-application-without-administrator-privileges-on-windows-7?forum=vbgeneral
アプリ名は、「RunAsBasicUser」です。
Form1にボタンを2つ配置しました。
「RunAsBasicUser」を管理者として実行します。
管理者特権は「はい」となっています。
Button2をクリックして、Terapadを起動させてみました。
管理者特権は「はい」となっています。
Button1をクリックして、Terapadを起動させてみました。
管理者特権は「いいえ」となっています。
上記ページのほとんどコピペですが、以下がソースコードです。
Imports System.Runtime.InteropServices Public Class Form1 <DllImport("advapi32.dll", SetLastError:=True)> Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean End Function ' <DllImport("advapi32.dll", SetLastError:=True)> ' Public Shared Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, ' ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, ' ByRef ReturnLength As System.UInt32) As Boolean ' End Function <DllImport("User32.dll", SetLastError:=True)> Public Shared Function GetShellWindow() As IntPtr End Function <DllImport("user32.dll", SetLastError:=True)> Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As IntPtr) As Integer End Function <DllImport("kernel32.dll")> Private Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr End Function <DllImport("advapi32.dll", SetLastError:=True)> Private Shared Function DuplicateTokenEx( ByVal ExistingTokenHandle As IntPtr, ByVal dwDesiredAccess As UInt32, ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal ImpersonationLevel As Integer, ByVal TokenType As Integer, ByRef DuplicateTokenHandle As System.IntPtr) As Boolean End Function <DllImport("advapi32.dll", SetLastError:=True)> Private Shared Function LookupPrivilegeValue(lpSystemName As String, lpName As String, ByRef lpLuid As LUID) As Boolean End Function ' Use this signature if you want the previous state information returned <DllImport("advapi32.dll", SetLastError:=True)> Private Shared Function AdjustTokenPrivileges( ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLengthInBytes As Integer, ByRef PreviousState As TOKEN_PRIVILEGES, ByRef ReturnLengthInBytes As Integer ) As Boolean End Function <DllImport("advapi32", SetLastError:=True, CharSet:=CharSet.Unicode)> Public Shared Function CreateProcessWithTokenW(hToken As IntPtr, dwLogonFlags As Integer, lpApplicationName As String, lpCommandLine As String, dwCreationFlags As Integer, lpEnvironment As IntPtr, lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean End Function <StructLayout(LayoutKind.Sequential)> Structure SECURITY_ATTRIBUTES Public nLength As Integer Public lpSecurityDescriptor As IntPtr Public bInheritHandle As Integer End Structure Structure TOKEN_PRIVILEGES Public PrivilegeCount As Integer Public TheLuid As LUID Public Attributes As Integer End Structure Structure LUID Public LowPart As UInt32 Public HighPart As UInt32 End Structure <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> Structure STARTUPINFO Public cb As Integer Public lpReserved As String Public lpDesktop As String Public lpTitle As String Public dwX As Integer Public dwY As Integer Public dwXSize As Integer Public dwYSize As Integer Public dwXCountChars As Integer Public dwYCountChars As Integer Public dwFillAttribute As Integer Public dwFlags As Integer Public wShowWindow As Short Public cbReserved2 As Short Public lpReserved2 As Integer Public hStdInput As Integer Public hStdOutput As Integer Public hStdError As Integer End Structure Structure PROCESS_INFORMATION Public hProcess As IntPtr Public hThread As IntPtr Public dwProcessId As Integer Public dwThreadId As Integer End Structure Public Const SE_PRIVILEGE_ENABLED = &H2L Public Const PROCESS_QUERY_INFORMATION = &H400 Public Const TOKEN_ASSIGN_PRIMARY = &H1 Public Const TOKEN_DUPLICATE = &H2 Public Const TOKEN_IMPERSONATE = &H4 Public Const TOKEN_QUERY = &H8 Public Const TOKEN_QUERY_SOURCE = &H10 Public Const TOKEN_ADJUST_PRIVILEGES = &H20 Public Const TOKEN_ADJUST_GROUPS = &H40 Public Const TOKEN_ADJUST_DEFAULT = &H80 Public Const TOKEN_ADJUST_SESSIONID = &H100 Public Const SecurityImpersonation = 2 Public Const TokenPrimary = 1 Public Const SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege" Private Sub RusAsBasicUser(sApplicationPath As String, sCommandLIne As String) Dim currentProcess As Process = Process.GetCurrentProcess 'Enable SeIncreaseQuotaPrivilege in this process. (This requires administrative privileges.) Dim hProcessToken As IntPtr = Nothing OpenProcessToken(currentProcess.Handle, TOKEN_ADJUST_PRIVILEGES, hProcessToken) Dim tkp As TOKEN_PRIVILEGES tkp.PrivilegeCount = 1 LookupPrivilegeValue(Nothing, SE_INCREASE_QUOTA_NAME, tkp.TheLuid) tkp.Attributes = SE_PRIVILEGE_ENABLED AdjustTokenPrivileges(hProcessToken, False, tkp, 0, Nothing, Nothing) 'Get window handle representing the desktop shell. This might not work if there is no shell window, or when 'using a custom shell. Also note that we're assuming that the shell is not running elevated. Dim hShellWnd As IntPtr = GetShellWindow() 'Get the ID of the desktop shell process. Dim dwShellPID As IntPtr GetWindowThreadProcessId(hShellWnd, dwShellPID) 'Open the desktop shell process in order to get the process token. Dim hShellProcess As IntPtr = OpenProcess(PROCESS_QUERY_INFORMATION, False, dwShellPID) Dim hShellProcessToken As IntPtr = Nothing Dim hPrimaryToken As IntPtr = Nothing 'Get the process token of the desktop shell. OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken) 'Duplicate the shell's process token to get a primary token. Dim dwTokenRights As Integer = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID DuplicateTokenEx(hShellProcessToken, dwTokenRights, Nothing, SecurityImpersonation, TokenPrimary, hPrimaryToken) Dim si As STARTUPINFO = Nothing Dim pi As PROCESS_INFORMATION = Nothing si.cb = Marshal.SizeOf(si) CreateProcessWithTokenW(hPrimaryToken, 0, sApplicationPath, sCommandLIne, 0, Nothing, Nothing, si, pi) End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click RusAsBasicUser("C:\Program Files (x86)\TeraPad\Terapad.exe", "") End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Process.Start("C:\Program Files (x86)\TeraPad\Terapad.exe") End Sub End Class
動作確認は、Windows10で行いました。