using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
public partial class Autofarm : Form
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_HANDLE_INFORMATION
public byte ObjectTypeNumber;
public int Object_Pointer;
public UInt32 GrantedAccess;
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_BASIC_INFORMATION
public int GrantedAccess;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
public int NameInformationLength;
public int TypeInformationLength;
public int SecurityDescriptorLength;
public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_NAME_INFORMATION
public UNICODE_STRING Name;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UNICODE_STRING
public ushort MaximumLength;
private static extern uint NtQuerySystemInformation(uint SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int nLength);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll")]
public static extern int CloseHandle(IntPtr hObject);
public static extern int NtQueryObject(IntPtr Handle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, ref int returnLength);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(int dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SetWindowText(IntPtr hWnd, string text);
private List<Process> processes = new List<Process>();
private List<string> magplantAutofarmer = new List<string>();
private List<string> multiboxes = new List<string>();
private bool selectAllChecked = false;
private System.Timers.Timer punchTimer;
private bool punchAllowed = true;
private string _growtopiaPath = "";
private string GrowtopiaPath
fileSelectDialog.InitialDirectory = _growtopiaPath;
fileNameDisplayer.Text = _growtopiaPath;
MessageBox.Show("Incorrect file specified", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
private static string ViewHandleName(WS.SYSTEM_HANDLE_INFORMATION shHandle, Process process)
IntPtr sourceProcessHandle = OpenProcess(0x1F0FFF, false, process.Id);
IntPtr targetHandle = IntPtr.Zero;
if (!DuplicateHandle(sourceProcessHandle, shHandle.Handle, GetCurrentProcess(), out targetHandle, 0, false, 0x2))
IntPtr basicQueryData = IntPtr.Zero;
WS.OBJECT_BASIC_INFORMATION basicInformationStruct = new WS.OBJECT_BASIC_INFORMATION();
WS.OBJECT_NAME_INFORMATION nameInformationStruct = new WS.OBJECT_NAME_INFORMATION();
basicQueryData = Marshal.AllocHGlobal(Marshal.SizeOf(basicInformationStruct));
NtQueryObject(targetHandle, 0, basicQueryData, Marshal.SizeOf(basicInformationStruct), ref nameInfoLength);
basicInformationStruct = (WS.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(basicQueryData, basicInformationStruct.GetType());
Marshal.FreeHGlobal(basicQueryData);
nameInfoLength = basicInformationStruct.NameInformationLength;
IntPtr nameQueryData = Marshal.AllocHGlobal(nameInfoLength);
while ((uint)(result = NtQueryObject(targetHandle, 1, nameQueryData, nameInfoLength, ref nameInfoLength)) == 0xc0000004)
Marshal.FreeHGlobal(nameQueryData);
nameQueryData = Marshal.AllocHGlobal(nameInfoLength);
nameInformationStruct = (WS.OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(nameQueryData, nameInformationStruct.GetType());
handlerName = new IntPtr(Convert.ToInt64(nameInformationStruct.Name.Buffer.ToString(), 10) >> 32);
handlerName = nameInformationStruct.Name.Buffer;
if (handlerName != IntPtr.Zero)
byte[] baTemp2 = new byte[nameInfoLength];
Marshal.Copy(handlerName, baTemp2, 0, nameInfoLength);
return Marshal.PtrToStringUni(Is64Bits() ? new IntPtr(handlerName.ToInt64()) : new IntPtr(handlerName.ToInt32()));
catch (AccessViolationException)
Marshal.FreeHGlobal(nameQueryData);
CloseHandle(targetHandle);
private void CloseProcessHandles(Process growtopia)
Console.WriteLine("Starting handle magic...");
statusMessage.Text = "Querying system handle information...";
IntPtr handlePointer = IntPtr.Zero;
int sysInfoLength = 0x10000;
IntPtr infoPointer = Marshal.AllocHGlobal(sysInfoLength);
while ((result = NtQuerySystemInformation(0x10, infoPointer, sysInfoLength, ref nLength)) == 0xc0000004)
Marshal.FreeHGlobal(infoPointer);
infoPointer = Marshal.AllocHGlobal(nLength);
byte[] baTemp = new byte[nLength];
Marshal.Copy(infoPointer, baTemp, 0, nLength);
sysHandleCount = Marshal.ReadInt64(infoPointer);
handlePointer = new IntPtr(infoPointer.ToInt64() + 8);
sysHandleCount = Marshal.ReadInt32(infoPointer);
handlePointer = new IntPtr(infoPointer.ToInt32() + 4);
statusMessage.Text = "Query received, processing the " + sysHandleCount + " results.";
WS.SYSTEM_HANDLE_INFORMATION handleInfoStruct;
List<WS.SYSTEM_HANDLE_INFORMATION> handles = new List<WS.SYSTEM_HANDLE_INFORMATION>();
for (long i = 0; i < sysHandleCount; i++)
handleInfoStruct = new WS.SYSTEM_HANDLE_INFORMATION();
handleInfoStruct = (WS.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(handlePointer, handleInfoStruct.GetType());
handlePointer = new IntPtr(handlePointer.ToInt64() + Marshal.SizeOf(handleInfoStruct) + 8);
handleInfoStruct = (WS.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(handlePointer, handleInfoStruct.GetType());
handlePointer = new IntPtr(handlePointer.ToInt64() + Marshal.SizeOf(handleInfoStruct));
if (handleInfoStruct.ProcessID != growtopia.Id)
string handleName = ViewHandleName(handleInfoStruct, growtopia);
if (handleName != null && handleName.StartsWith(@"\Sessions\") && handleName.EndsWith(@"\BaseNamedObjects\Growtopia"))
handles.Add(handleInfoStruct);
Console.WriteLine("PID {0,7} Pointer {1,12} Type {2,4} Name {3}", handleInfoStruct.ProcessID.ToString(), handleInfoStruct.Object_Pointer.ToString(), handleInfoStruct.ObjectTypeNumber.ToString(), handleName);
Console.WriteLine("Closing mutexes?");
foreach (WS.SYSTEM_HANDLE_INFORMATION handle in handles)
statusMessage.Text = "Query finished, " + sysHandleCount + " results processed.";
Console.WriteLine("Handle closed.");
private void SuspendProcess(Process process)
foreach (ProcessThread pT in process.Threads)
IntPtr pOpenThread = OpenThread(0x0002, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
SuspendThread(pOpenThread);
CloseHandle(pOpenThread);
Console.WriteLine("SUSPENDED");
private void ResumeProcess(Process process)
foreach (ProcessThread pT in process.Threads)
IntPtr pOpenThread = OpenThread(0x0002, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
suspendCount = ResumeThread(pOpenThread);
while (suspendCount > 0);
CloseHandle(pOpenThread);
private void CloseMutex(WS.SYSTEM_HANDLE_INFORMATION handle)
if (!DuplicateHandle(Process.GetProcessById(handle.ProcessID).Handle, handle.Handle, IntPtr.Zero, out targetHandle, 0, false, 0x1))
MessageBox.Show("Failed to close mutex: " + Marshal.GetLastWin32Error(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Console.WriteLine("Mutex was killed");
private void Autofarmer_Load(object sender, EventArgs e)
GrowtopiaPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\Appdata\Local\Growtopia\Growtopia.exe";
autoFarmerType.SelectedIndex = 0;
multiboxToggle.SelectedIndex = 0;
checkbox = new CheckBox();
checkbox.Size = new System.Drawing.Size(15, 15);
checkbox.BackColor = Color.Transparent;
checkbox.Padding = new Padding(0);
checkbox.Margin = new Padding(0);
processList.Controls.Add(checkbox);
DataGridViewHeaderCell header = processList.Columns["Checkbox"].HeaderCell;
checkbox.Location = new Point(12, 10);
checkbox.CheckedChanged += new EventHandler(SelectAll);
punchTimer = new System.Timers.Timer(150);
punchTimer.Elapsed += new System.Timers.ElapsedEventHandler(PunchClick);
Process[] previousProcesses = Process.GetProcessesByName("Growtopia");
List<Process> sortedProcesses = previousProcesses.OrderBy(s => s.MainWindowTitle).ToList();
foreach (Process sortedProcess in sortedProcesses)
processes.Add(sortedProcess);
processList.Rows[processes.Count - 1].Cells["Number"].Value = processes.Count;
processList.Rows[processes.Count - 1].Cells["Active"].Value = "None";
processList.Rows[processes.Count - 1].Cells["Multibox"].Value = "Disabled";
processList.Rows[processes.Count - 1].Cells["PID"].Value = sortedProcess.Id;
if (processes.Count == 6)
checkbox.Location = new Point(4, 10);
openGTButton.Text = "Open GT (" + processes.Count + " open)";
statusMessage.Text = "Previous growtopias opened!";
private void SelectAll(object sender, EventArgs e)
selectAllChecked = !selectAllChecked;
foreach (DataGridViewRow row in processList.Rows)
DataGridViewCheckBoxCell checkbox = (DataGridViewCheckBoxCell)row.Cells["Checkbox"];
checkbox.Value = selectAllChecked;
checkbox.Value = !selectAllChecked;
checkbox.Value = selectAllChecked;
processList.RefreshEdit();
private void changeAutofarmer(object sender, EventArgs e)
string selectedOption = autoFarmerType.SelectedItem.ToString();
foreach (DataGridViewRow row in processList.Rows)
if (Convert.ToBoolean(row.Cells["Checkbox"].Value))
previousActive = row.Cells["Active"].Value.ToString();
row.Cells["Active"].Value = selectedOption;
if (selectedOption == "None")
if (previousActive == "Magplant")
magplantAutofarmer.Remove(row.Cells["Number"].Value.ToString());
else if (selectedOption == "Magplant")
if (previousActive == "None")
magplantAutofarmer.Add(row.Cells["Number"].Value.ToString());
private void changeMultibox(object sender, EventArgs e)
string selectedOption = multiboxToggle.SelectedItem.ToString();
foreach (DataGridViewRow row in processList.Rows)
if (Convert.ToBoolean(row.Cells["Checkbox"].Value))
previousOption = row.Cells["Multibox"].Value.ToString();
row.Cells["Multibox"].Value = selectedOption;
if (selectedOption == "Disabled" && previousOption == "Enabled")
multiboxes.Remove(row.Cells["Number"].Value.ToString());
else if (selectedOption == "Enabled" && previousOption == "Disabled")
multiboxes.Add(row.Cells["Number"].Value.ToString());
private void SelectFile(object sender, EventArgs e)
DialogResult result = fileSelectDialog.ShowDialog();
if (result == DialogResult.OK)
GrowtopiaPath = fileSelectDialog.FileName;
private void OpenGrowtopia(object sender, EventArgs e)
List<Process> suspendedProcesses = new List<Process>();
foreach (Process process in processes)
suspendedProcesses.Add(process);
for (int i = 0; i < numberInput.Value; i++)
SuspendProcess(processes[processes.Count - 1]);
suspendedProcesses.Add(processes[processes.Count - 1]);
CloseProcessHandles(processes[processes.Count - 1]);
Process growtopia = new Process();
fileSelectButton.Enabled = false;
openGTButton.Enabled = false;
growtopia.StartInfo.FileName = GrowtopiaPath;
processes.Add(growtopia);
processList.Rows[processes.Count - 1].Cells["Number"].Value = processes.Count;
processList.Rows[processes.Count - 1].Cells["Active"].Value = "None";
processList.Rows[processes.Count - 1].Cells["Multibox"].Value = "Disabled";
processList.Rows[processes.Count - 1].Cells["PID"].Value = growtopia.Id;
if (processes.Count == 6)
checkbox.Location = new Point(4, 10);
growtopia.WaitForInputIdle();
SetWindowText(growtopia.MainWindowHandle, "Growtopia " + processes.Count);
foreach (Process process in suspendedProcesses)
openGTButton.Text = "Open GT (" + processes.Count + " open)";
statusMessage.Text = "Growtopias opened!";
openGTButton.Enabled = true;
MessageBox.Show("Please set a file path for Growtopia!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
private static bool Is64Bits()
return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false;
private void SendClick(Process process, int x, int y, int? dx = null, int? dy = null)
if (dx == null && dy == null)
IntPtr handle = process.MainWindowHandle;
SendMessage(handle, 0x201, new IntPtr(0x0001), (IntPtr)((y << 16) | (x & 0xffff)));
SendMessage(handle, 0x202, new IntPtr(0x0001), (IntPtr)((dy << 16) | (dx & 0xffff)));
private bool toggleAutofarmerBool = false;
private bool toggleMultiboxBool = false;
private void PunchClick(object source, System.Timers.ElapsedEventArgs e)
Process[] gtProcesses = Process.GetProcessesByName("Growtopia");
System.Threading.Tasks.Parallel.ForEach(processes, p =>
if (p.MainWindowTitle == "Growtopia")
pNum = p.MainWindowTitle.Remove(0, p.MainWindowTitle.IndexOf(' ') + 1);
if (magplantAutofarmer.Contains(pNum))
private void ToggleAutofarmers(object sender, EventArgs e)
toggleAutofarmerBool = !toggleAutofarmerBool;
toggleAutofarmer.Text = toggleAutofarmerBool ? "Autofarmers: On" : "Autofarmers: Off";
punchTimer.Enabled = toggleAutofarmerBool;
private void ToggleMultiboxes(object sender, EventArgs e)
toggleMultiboxBool = !toggleMultiboxBool;
toggleMultibox.Text = toggleMultiboxBool ? "Multibox: On" : "Multibox: Off";
private void button1_Click(object sender, EventArgs e)