Devpia, C#포럼에서 어떤 분께서 프로세스(실행중인 프로그램)에 대한 정보를 가져오는 질문에 대해서
시삽인 남정현님께서 답한 내용입니다.
Vista 및 7등 Windows계열에서는 권한 문제때문에 프로세스 정보를 얻어오지 못할 수 있다고 합니다.
아래 기재된 링크를 통해서 UAC권한상승에 대한 문제를 해결하고 아래 샘플코드에서 프로세스 정보에 접근하는 방법을 소개 하고 있습니다.
- 이하 원문
다음의 샘플 코드를 참고하시면 되겠습니다. 아래 코드는, Windows Vista 이후의 운영 체제의 경우, 권한이 없기 때문에 프로세스에 대한 토큰을 열 수 없어서 사용자 이름을 가져오지 못할 수 있으며, 이를 해결하려면 해당 프로그램을 UAC 매니페스트를 지정하여 권한 상승 (Elevation) 처리를 해야 합니다. UAC 권한 상승에 대한 자세한 정보는 http://sjpison.tistory.com/68 를 참고하시면 도움될 것입니다.
namespace ConsoleApplication1
{
using System;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
static class ProcessExtension
{
#region P/Invoke
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupAccountSid(
string lpSystemName,
[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);
#endregion // P/Invoke
#region Constants
[NonSerialized]
public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000u;
[NonSerialized]
public const uint STANDARD_RIGHTS_READ = 0x00020000u;
[NonSerialized]
public const uint TOKEN_ASSIGN_PRIMARY = 0x0001u;
[NonSerialized]
public const uint TOKEN_DUPLICATE = 0x0002u;
[NonSerialized]
public const uint TOKEN_IMPERSONATE = 0x0004u;
[NonSerialized]
public const uint TOKEN_QUERY = 0x0008u;
[NonSerialized]
public const uint TOKEN_QUERY_SOURCE = 0x0010u;
[NonSerialized]
public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020u;
[NonSerialized]
public const uint TOKEN_ADJUST_GROUPS = 0x0040u;
[NonSerialized]
public const uint TOKEN_ADJUST_DEFAULT = 0x0080u;
[NonSerialized]
public const uint TOKEN_ADJUST_SESSIONID = 0x0100u;
[NonSerialized]
public const uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
[NonSerialized]
public const uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID);
[NonSerialized]
public const uint NO_ERROR = 0u;
[NonSerialized]
public const uint ERROR_INSUFFICIENT_BUFFER = 122u;
#endregion // Constants
#region Enum Values
[Serializable]
public enum TOKEN_INFORMATION_CLASS : uint
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
[Serializable]
public enum SID_NAME_USE : uint
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}
#endregion // Enum Values
#region Structures
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_USER
{
public SID_AND_ATTRIBUTES User;
}
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public int Attributes;
}
#endregion // Structures
public static byte[] GetSIDByteArr(Process targetProcess)
{
int MAX_INTPTR_BYTE_ARR_SIZE = 512;
IntPtr tokenHandle = IntPtr.Zero;
IntPtr processHandle = IntPtr.Zero;
byte[] sidBytes;
try
{
try { processHandle = targetProcess.Handle; }
catch { return null; }
// Get the Process Token
if (!OpenProcessToken(processHandle, TOKEN_READ, out tokenHandle))
throw new Exception("Could not get process token. Win32 Error Code: " + Marshal.GetLastWin32Error());
uint tokenInfoLength = 0;
bool result;
result = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, tokenInfoLength, out tokenInfoLength); // get the token info length
IntPtr tokenInfo = Marshal.AllocHGlobal((int)tokenInfoLength);
result = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenUser, tokenInfo, tokenInfoLength, out tokenInfoLength); // get the token info
// Get the User SID
if (result)
{
TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInfo, typeof(TOKEN_USER));
sidBytes = new byte[MAX_INTPTR_BYTE_ARR_SIZE]; // Since I don't yet know how to be more precise w/ the size of the byte arr, it is being set to 512
Marshal.Copy(tokenUser.User.Sid, sidBytes, 0, MAX_INTPTR_BYTE_ARR_SIZE); // get a byte[] representation of the SID
}
else
throw new Exception("Could not get process token. Win32 Error Code: " + Marshal.GetLastWin32Error());
return sidBytes;
}
finally
{
if (!tokenHandle.Equals(IntPtr.Zero))
CloseHandle(tokenHandle);
}
}
public static bool GetUserAndDomainName(Process targetProcess, string targetSystemName, out string userName, out string domainName, out int win32ErrorCode)
{
StringBuilder name = new StringBuilder();
uint cchName = (uint)name.Capacity;
StringBuilder referencedDomainName = new StringBuilder();
uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
SID_NAME_USE sidUse;
byte[] sid = GetSIDByteArr(targetProcess);
if (sid == null)
{
win32ErrorCode = Marshal.GetLastWin32Error();
userName = null;
domainName = null;
return false;
}
win32ErrorCode = (int)NO_ERROR;
if (!LookupAccountSid(targetSystemName, sid, name, ref cchName,
referencedDomainName, ref cchReferencedDomainName, out sidUse))
{
win32ErrorCode = Marshal.GetLastWin32Error();
if (win32ErrorCode == ERROR_INSUFFICIENT_BUFFER)
{
name.EnsureCapacity((int)cchName);
referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
win32ErrorCode = (int)NO_ERROR;
if (!LookupAccountSid(targetSystemName, sid, name, ref cchName,
referencedDomainName, ref cchReferencedDomainName, out sidUse))
win32ErrorCode = Marshal.GetLastWin32Error();
}
}
if (win32ErrorCode == 0)
{
userName = name.ToString();
domainName = referencedDomainName.ToString();
return true;
}
else
{
userName = null;
domainName = null;
return false;
}
}
public static bool GetUserAndDomainName(Process targetProcess, string targetSystemName, out string userName, out string domainName)
{
int win32ErrorCodeToIgnore = 0;
return GetUserAndDomainName(targetProcess, targetSystemName, out userName, out domainName, out win32ErrorCodeToIgnore);
}
public static bool GetUserAndDomainName(Process targetProcess, out string userName, out string domainName, int win32ErrorCode)
{
return GetUserAndDomainName(targetProcess, null, out userName, out domainName, out win32ErrorCode);
}
public static bool GetUserAndDomainName(Process targetProcess, out string userName, out string domainName)
{
int win32ErrorCodeToIgnore = 0;
return GetUserAndDomainName(targetProcess, null, out userName, out domainName, out win32ErrorCodeToIgnore);
}
}
class Program
{
[STAThread]
static void Main(string[] args)
{
foreach (Process eachProcess in Process.GetProcesses())
{
string imageName = eachProcess.ProcessName;
string userName = null;
string domainName = null;
string result = null;
if (ProcessExtension.GetUserAndDomainName(eachProcess, out userName, out domainName))
result = userName + "@" + domainName;
else
result = "(Access Denied)";
Console.WriteLine("{0} / {1}", imageName, result);
}
}
}
}
'Program > C#' 카테고리의 다른 글
WMI를 이용한 PC고유 정보 알아내기 (0) | 2010.03.19 |
---|---|
.NET CF에서 WndProc 사용법 (0) | 2010.03.19 |
DoubleBuffer구현을 통한 잔상없애기 (0) | 2010.03.19 |
PictureBox에서 Image 깜빡이는 효과주기. (0) | 2010.03.19 |
타임 서버에서 데이터 받아오기 (0) | 2010.03.19 |