//------------------------------------------------------------------------------
/// <copyright from='2004' to='2005' company='Christian Forsberg'>
///		Copyright (c) Christian Forsberg, chris@businessanyplace.net.
///
///   This program is distributed in the hope that it will be useful,
///   but WITHOUT ANY WARRANTY; without even the implied warranty of
///   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
/// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Text;

namespace TaskManager
{
	#region Process class
	/// <summary>
	/// This is the Process class.
	/// </summary>
	public class Process
	{
		private string processName;
		private IntPtr processId;
		private int threadCount;
		private int baseAddress;

		public Process()
		{			
		}

		private Process(IntPtr processId, string processName, int threadCount, int baseAddress)
		{	
			this.processId = processId;
			this.processName = processName;
			this.threadCount = threadCount;
			this.baseAddress = baseAddress;
		}

		public override string ToString()
		{
			return processName;
		}

		public int BaseAddress
		{
			get	{	return baseAddress; }
		}

		public int ThreadCount
		{
			get	{	return threadCount;	}
		}

		public IntPtr ProcessId
		{
			get	{	return processId; }
		}

		public string ProcessName
		{
			get	{	return processName;	}
		}

		public void Kill()
		{
			IntPtr hProcess;
		
			hProcess = OpenProcess(PROCESS_TERMINATE, false, (int) processId);

			if(hProcess != (IntPtr) INVALID_HANDLE_VALUE) 
			{
				bool bRet;
				bRet = TerminateProcess(hProcess, 0);
				CloseHandle(hProcess);
			}
		}

		public static Process[] GetProcesses()
		{
			ArrayList procList = new ArrayList();

			IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

			if((int)handle > 0)
			{
				try
				{
					PROCESSENTRY32 peCurrent;
					PROCESSENTRY32 pe32 = new PROCESSENTRY32();
					byte[] peBytes = pe32.ToByteArray();
					int retval = Process32First(handle, peBytes);

					while(retval == 1)
					{
						peCurrent = new PROCESSENTRY32(peBytes);
						Process proc = new Process(new IntPtr((int)peCurrent.PID), peCurrent.Name, (int)peCurrent.ThreadCount, (int)peCurrent.BaseAddress);
						procList.Add(proc);
						retval = Process32Next(handle, peBytes);
					}
				}
				catch(Exception ex)
				{
					throw new Exception("Exception: " + ex.Message);
				}
				CloseToolhelp32Snapshot(handle); 
				return (Process[])procList.ToArray(typeof(Process));
			}
			else
			{
				throw new Exception("Unable to get processes!");
			}
		}
		#endregion

		#region PROCESSENTRY32 implementation

		private class PROCESSENTRY32
		{
			private const int SizeOffset = 0;
			private const int UsageOffset = 4;
			private const int ProcessIDOffset=8;
			private const int DefaultHeapIDOffset = 12;
			private const int ModuleIDOffset = 16;
			private const int ThreadsOffset = 20;
			private const int ParentProcessIDOffset = 24;
			private const int PriClassBaseOffset = 28;
			private const int dwFlagsOffset = 32;
			private const int ExeFileOffset = 36;
			private const int MemoryBaseOffset = 556;
			private const int AccessKeyOffset = 560;
			private const int Size = 564;
			private const int MAX_PATH = 260;

			public uint dwSize; 
			public uint cntUsage; 
			public uint th32ProcessID; 
			public uint th32DefaultHeapID; 
			public uint th32ModuleID; 
			public uint cntThreads; 
			public uint th32ParentProcessID; 
			public long pcPriClassBase; 
			public uint dwFlags; 
			public string szExeFile;
			public uint th32MemoryBase;
			public uint th32AccessKey;

      public PROCESSENTRY32()
      {
      }

			public PROCESSENTRY32(byte[] aData)
			{
				dwSize = GetUInt(aData, SizeOffset);
				cntUsage = GetUInt(aData, UsageOffset);
				th32ProcessID = GetUInt(aData, ProcessIDOffset);
				th32DefaultHeapID = GetUInt(aData, DefaultHeapIDOffset);
				th32ModuleID = GetUInt(aData, ModuleIDOffset);
				cntThreads = GetUInt(aData, ThreadsOffset);
				th32ParentProcessID = GetUInt(aData, ParentProcessIDOffset);
				pcPriClassBase = (long) GetUInt(aData, PriClassBaseOffset);
				dwFlags = GetUInt(aData, dwFlagsOffset);
				szExeFile = GetString(aData, ExeFileOffset, MAX_PATH);
				th32MemoryBase = GetUInt(aData, MemoryBaseOffset);
				th32AccessKey = GetUInt(aData, AccessKeyOffset);
			}

			#region Conversion functions
			private static uint GetUInt(byte[] aData, int Offset)
			{
				return BitConverter.ToUInt32(aData, Offset);
			}
		
			private static void SetUInt(byte[] aData, int Offset, int Value)
			{
				byte[] buint = BitConverter.GetBytes(Value);
				Buffer.BlockCopy(buint, 0, aData, Offset, buint.Length);
			}

			private static ushort GetUShort(byte[] aData, int Offset)
			{
				return BitConverter.ToUInt16(aData, Offset);
			}
		
			private static void SetUShort(byte[] aData, int Offset, int Value)
			{
				byte[] bushort = BitConverter.GetBytes((short)Value);
				Buffer.BlockCopy(bushort, 0, aData, Offset, bushort.Length);
			}
		
			private static string GetString(byte[] aData, int Offset, int Length)
			{
				String sReturn =  Encoding.Unicode.GetString(aData, Offset, Length);
				return sReturn;
			}
		
			private static void SetString(byte[] aData, int Offset, string Value)
			{
				byte[] arr = Encoding.ASCII.GetBytes(Value);
				Buffer.BlockCopy(arr, 0, aData, Offset, arr.Length);
			}
			#endregion

			public byte[] ToByteArray()
			{
				byte[] aData;
				aData = new byte[Size];
				SetUInt(aData, SizeOffset, Size);
				return aData;
			}

			public string Name
			{
				get	{	return szExeFile.Substring(0, szExeFile.IndexOf('\0'));	}
			}

			public ulong PID
			{
				get	{	return th32ProcessID;	}
			}

			public ulong BaseAddress
			{
				get	{	return th32MemoryBase; }
			}

			public ulong ThreadCount
			{
				get	{	return cntThreads;	}
			}
		}
		#endregion

		#region PInvoke declarations
		private const int TH32CS_SNAPPROCESS = 0x00000002;
		[DllImport("toolhelp.dll")]
		public static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processid);
		[DllImport("toolhelp.dll")]
		public static extern int CloseToolhelp32Snapshot(IntPtr handle);
		[DllImport("toolhelp.dll")]
		public static extern int Process32First(IntPtr handle, byte[] pe);
		[DllImport("toolhelp.dll")]
		public static extern int Process32Next(IntPtr handle, byte[] pe);
		[DllImport("coredll.dll")]
		private static extern IntPtr OpenProcess(int flags, bool fInherit, int PID);
		private const int PROCESS_TERMINATE = 1;
		[DllImport("coredll.dll")]
		private static extern bool TerminateProcess(IntPtr hProcess, uint ExitCode);
		[DllImport("coredll.dll")]
		private static extern bool CloseHandle(IntPtr handle);
		private const int INVALID_HANDLE_VALUE = -1;
		#endregion
	}
}
