unit MainUnit;

//{$MODE Delphi}
{$mode objfpc}{$H+}

interface

uses
  {$ifdef darwin}
  LResources, LCLIntf, LCLProc, MacOSAll,MacOSXPosix, LMessages, Classes, Forms, Controls, Messages,
  ComCtrls, stdctrls,sysutils,    graphics,menus, dialogs, extctrls, math, buttons,
  ImgList, ActnList, registry, Clipbrd, NewKernelHandler, Assemblerunit,
  symbolhandler,autoassembler, addresslist, CustomTypeHandler, MemoryRecordUnit,memscan,
  SaveFirstScan, foundlisthelper, disassembler, tablist, simpleaobscanner,frmSelectionlistunit,
  lua, LuaHandler, lauxlib, lualib,CEDebugger,debughelper ,speedhack2, groupscancommandparser,
  frmautoinjectunit, commonTypeDefs, unrandomizer,savedscanhandler,luafile,hotkeyhandler,
  genericHotkey,LazLogger,lcltype,syncobjs, SyncObjs2,FrmMemoryRecordDropdownSettingsUnit,
  ceguicomponents,formdesignerunit,xmlutils,vartypestrings,plugin,byteinterpreter,
  MenuItemExtra,frmgroupscanalgoritmgeneratorunit

  , macport,LCLVersion, UTF8Process, macportdefines, fgl, networkInterfaceApi,
  networkInterface,

  betterControls;     //last one
  {$endif}

  {$ifdef windows}
  jwaWindows, Windows, LCLIntf, LCLProc, Messages, SysUtils, Classes, SyncObjs,
  SyncObjs2, Graphics,
  Controls, Forms, ComCtrls, StdCtrls, Menus, Buttons, shellapi,
  imagehlp, ExtCtrls, Dialogs, Clipbrd, CEDebugger, kerneldebugger, assemblerunit,
  hotkeyhandler, registry, Math, ImgList, commctrl, NewKernelHandler,
  unrandomizer, symbolhandler, ActnList, LResources, hypermode, memscan,
  autoassembler, plugin, savefirstscan, menuitemExtra, speedhack2, AccessCheck,
  foundlisthelper, disassembler, peinfounit, PEInfoFunctions,
  simpleaobscanner, pointervaluelist, ManualModuleLoader, debughelper,
  frmRegistersunit, ctypes, addresslist, addresslisthandlerunit, memoryrecordunit,
  windows7taskbar, tablist, DebuggerInterface, vehdebugger, tableconverter,
  customtypehandler, lua, luahandler, lauxlib, lualib, frmSelectionlistunit,
  htmlhelp, win32int, {defaulttranslator,} fileaccess, formdesignerunit,
  ceguicomponents, frmautoinjectunit, cesupport, trainergenerator, genericHotkey,
  luafile, xmplayer_server, sharedMemory{$ifdef windows}, win32proc{$endif},
  vmxfunctions, FileUtil, networkInterfaceApi, networkconfig, d3dhookUnit, PNGcomn,
  FPimage, byteinterpreter, frmgroupscanalgoritmgeneratorunit, vartypestrings,
  groupscancommandparser, GraphType, IntfGraphics, RemoteMemoryManager,
  DBK64SecondaryLoader, savedscanhandler, debuggertypedefinitions, networkInterface,
  FrmMemoryRecordDropdownSettingsUnit, xmlutils, zstream, zstreamext, commonTypeDefs,
  VirtualQueryExCache, LazLogger, LazUTF8, LCLVersion, fgl, betterControls;
  {$endif}
//the following are just for compatibility



const
  copypasteversion = 4;

const
  wm_freedebugger = WM_USER + 1;

const
  //wm_scandone = WM_USER + 2;
  wm_pluginsync = WM_USER + 3;

  wm_showerror = WM_USER + 4;

//scantabs
type
  TProcessOpenedEvent=procedure(processid: THandle; processhandle: DWORD; caption: string) of object;


  TScanState = record
    alignsizechangedbyuser: boolean;
    compareToSavedScan: boolean;
    currentlySelectedSavedResultname: string; //I love long variable names

    compareToColumn: integer;

    cbCompareToSavedScan: record
      visible: boolean;
    end;
    lblcompareToSavedScan: record
      Caption: string;
      Visible: boolean;
    end;




    FromAddress: record
      Text: string;
    end;

    ToAddress: record
      Text: string;
    end;

    cbReadOnly: record
      Checked: boolean;
    end;

    cbfastscan: record
      Checked: boolean;
    end;

    cbunicode: record
      checked: boolean;
      visible: boolean;
    end;

    cbcodepage: record
      checked: boolean;
      visible: boolean;
    end;

    cbnot: record
      checked: boolean;
      visible: boolean;
    end;

    cbLuaformula: record
      checked: boolean;
      visible: boolean;
    end;

    cbNewLuaState: record
      checked: boolean;
      visible: boolean;
    end;

    cbRepeatUntilStopped: record
      checked: boolean;
      visible: boolean;
    end;


    cbCaseSensitive: record
      checked: boolean;
      visible: boolean;
    end;

    edtAlignment: record
      Text: string;
      Enabled: boolean;
    end;

    rbFsmAligned:record
      checked: boolean;
    end;


    cbpercentage: record
      exists: boolean;
      Checked: boolean;
    end;


    floatpanel: record
      Visible: boolean;
      rounded: boolean;
      roundedextreme: boolean;
      truncated: boolean;
    end;

    rbbit: record
      Visible: boolean;
      Enabled: boolean;
      Checked: boolean;
    end;

    rbdec: record
      Visible: boolean;
      Enabled: boolean;
      Checked: boolean;
    end;

    cbHexadecimal: record
      Visible: boolean;
      Checked: boolean;
      Enabled: boolean;
    end;

    gbScanOptionsEnabled: boolean;

    scantype: record
      options: string;
      ItemIndex: integer;
      Enabled: boolean;
      dropdowncount: integer;
    end;

    vartype: record
      //options: TStringList;
      ItemIndex: integer;
      Enabled: boolean;
    end;


    memscan: TMemscan;
    foundlist: TFoundList;


    scanvalue: record
      Visible: boolean;
      Text: string;
    end;

    scanvalue2: record
      exists: boolean;
      Text: string;
    end;

    firstscanstate: record
      Caption: string;
      Enabled: boolean;
    end;

    nextscanstate: record
      Enabled: boolean;
    end;

    btnFirst: record
      tag: integer;
    end;

    foundlist3: record
      ItemIndex: integer;
    end;
    foundlistDisplayOverride: integer;


    cbfloatSimple: record
      Checked: boolean;
    end;

  end;
  PScanState = ^TScanState;


type
  TFlash = class(TThread)
  public
    procedure Execute; override;
    procedure col;
  end;


type
  TToggleWindows = class(TThread)
  private
  public
    constructor Create(CreateSuspended: boolean);
    procedure Execute; override;
  end;

type
  TAutoAttachThread=class(TThread)
  private
    fInterval: integer;
  public
    CurrentProcessList: TStringList;
    procedure autoattachcheck;
    constructor Create(CreateSuspended: boolean);
    procedure Execute; override;
  published
    property Interval: integer read fInterval write fInterval;
  end;



type
  grouptype = array[1..6] of boolean;


type

  { TMainForm }

  TFreezeThread=class(TThread)
  private
    fAddressList: TAddresslist;
    freezeInterval: integer;
    procedure applyFreeze;
  public
    procedure Execute; override;
    constructor Create(AddressList: TAddresslist; interval: integer);
  end;

  //TPreviousResultList=specialize TFPGList<TSavedScanHandler>;

  TMainForm = class(TForm)
    actOpenLuaEngine: TAction;
    actOpenDissectStructure: TAction;
    btnSetSpeedhack2: TButton;
    btnAddAddressManually: TButton;
    btnMemoryView: TButton;
    cbCaseSensitive: TCheckBox;
    cbCopyOnWrite: TCheckBox;
    cbExecutable: TCheckBox;
    cbFastScan: TCheckBox;
    cbFloatSimple: TCheckBox;
    cbHexadecimal: TCheckBox;
    cbPauseWhileScanning: TCheckBox;
    cbSpeedhack: TCheckBox;
    cbUnicode: TCheckBox;
    cbUnrandomizer: TCheckBox;
    cbWritable: TCheckBox;
    cbpercentage: TCheckBox;
    cbNot: TCheckBox;
    cbCodePage: TCheckBox;
    cbRepeatUntilStopped: TCheckBox;
    cbCompareToSavedScan: TCheckBox;
    cbLuaFormula: TCheckBox;
    cbNewLuaState: TCheckBox;
    cbPresentMemoryOnly: TCheckBox;
    ColorDialog1: TColorDialog;
    CreateGroup: TMenuItem;
    FromAddress: TEdit;
    andlabel: TLabel;
    lblcompareToSavedScan: TLabel;
    miTestAccessViolationThread: TMenuItem;
    miTriggerAccessViolation: TMenuItem;
    MenuItem16: TMenuItem;
    MenuItem17: TMenuItem;
    MenuItem18: TMenuItem;
    miClearWorkingSet: TMenuItem;
    miNetworkReadUseProcMem: TMenuItem;
    miNetworkReadUsePtrace: TMenuItem;
    miNetworkReadUseVmread: TMenuItem;
    miNetworkWriteUseProcMem: TMenuItem;
    miNetworkWriteUsePtrace: TMenuItem;
    miNetworkWriteUseVmWrite: TMenuItem;
    miDeleteSavedScanResults: TMenuItem;
    miOnlyShowCurrentCompareToColumn: TMenuItem;
    miLoadRecent: TMenuItem;
    miAlwaysHideChildren: TMenuItem;
    miFoundListPreferences: TMenuItem;
    N2: TMenuItem;
    mfImageList: TImageList;
    lblSigned: TLabel;
    MainMenu2: TMainMenu;
    miTutorial64: TMenuItem;
    MenuItem14: TMenuItem;
    MenuItem15: TMenuItem;
    Copyselectedaddresses1: TMenuItem;
    miAutoAssembleErrorMessage: TMenuItem;
    miLuaDocumentation: TMenuItem;
    miForgotScan: TMenuItem;
    miDotNET: TMenuItem;
    miGetDotNetObjectList: TMenuItem;
    miDBVMFindWhatWritesOrAccesses: TMenuItem;
    pmPresentMemoryOnly: TPopupMenu;
    sep2: TMenuItem;
    miChangeValueBack: TMenuItem;
    miSignTable: TMenuItem;
    miSaveFile: TMenuItem;
    miAsyncScript: TMenuItem;
    miFlFindWhatAccesses: TMenuItem;
    MenuItem13: TMenuItem;
    miFlFindWhatWrites: TMenuItem;
    miLanguages: TMenuItem;
    ScanText2: TLabel;
    scanvalue2: TEdit;
    sbClearActiveMemory: TSpeedButton;
    tLuaGCPassive: TTimer;
    tLuaGCActive: TTimer;
    ToAddress: TEdit;
    editSH2: TEdit;
    edtAlignment: TEdit;
    Foundlist3: TListView;
    ImageList2: TImageList;
    Label1: TLabel;
    Label2: TLabel;
    Label54: TLabel;
    lblSH0: TLabel;
    lblSH20: TLabel;
    MenuItem1: TMenuItem;
    MenuItem10: TMenuItem;
    MenuItem11: TMenuItem;
    miEnableLCLDebug: TMenuItem;
    miDisassemble: TMenuItem;
    miBindDeactivation: TMenuItem;
    miScanDirtyOnly: TMenuItem;
    miScanPagedOnly: TMenuItem;
    miGeneratePointermap: TMenuItem;
    miDisplayHex: TMenuItem;
    miNetwork: TMenuItem;
    miCompression: TMenuItem;
    miManualExpandCollapse: TMenuItem;
    miSetDropdownOptions: TMenuItem;
    miSave: TMenuItem;
    miSnapshothandler: TMenuItem;
    miSetupSnapshotKeys: TMenuItem;
    miDisplayDefault: TMenuItem;
    miDisplayByte: TMenuItem;
    miDisplay2Byte: TMenuItem;
    miDisplay4Byte: TMenuItem;
    miDisplayFloat: TMenuItem;
    miDisplayDouble: TMenuItem;
    miDisplay8Byte: TMenuItem;
    MenuItem19: TMenuItem;
    miShowPreviousValue: TMenuItem;
    MenuItem4: TMenuItem;
    miShowCustomTypeDebug: TMenuItem;
    miShowAsSigned: TMenuItem;
    miOpenFile: TMenuItem;
    MenuItem8: TMenuItem;
    miTutorial: TMenuItem;
    miLockMouseInGame: TMenuItem;
    miChangeValue: TMenuItem;
    miAddAddress: TMenuItem;
    miAllowCollapse: TMenuItem;
    miSetCrosshair: TMenuItem;
    miWireframe: TMenuItem;
    miZbuffer: TMenuItem;
    miHookD3D: TMenuItem;
    mi3d: TMenuItem;
    miUndoValue: TMenuItem;
    miPresetWritable: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem3: TMenuItem;
    miShowLuaScript: TMenuItem;
    MenuItem5: TMenuItem;
    miPresetAll: TMenuItem;
    miAddFile: TMenuItem;
    MenuItem9: TMenuItem;
    miResyncFormsWithLua: TMenuItem;
    miCreateLuaForm: TMenuItem;
    miLuaFormsSeperator: TMenuItem;
    miTable: TMenuItem;
    miSaveScanresults: TMenuItem;
    MenuItem6: TMenuItem;
    MenuItem7: TMenuItem;
    miShowAsBinary: TMenuItem;
    miZeroTerminate: TMenuItem;
    miResetRange: TMenuItem;
    miChangeColor: TMenuItem;
    miGroupconfig: TMenuItem;
    miDefineNewCustomTypeLua: TMenuItem;
    miDeleteCustomType: TMenuItem;
    miHideChildren: TMenuItem;
    miBindActivation: TMenuItem;
    miRecursiveSetValue: TMenuItem;
    miDefineNewCustomType: TMenuItem;
    miEditCustomType: TMenuItem;
    miRenameTab: TMenuItem;
    miTablistSeperator: TMenuItem;
    miCloseTab: TMenuItem;
    miAddTab: TMenuItem;
    miFreezePositive: TMenuItem;
    miFreezeNegative: TMenuItem;
    Panel1: TPanel;
    Panel10: TPanel;
    Panel14: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
    Panel6: TPanel;
    Panel8: TPanel;
    Panel9: TPanel;
    pnlFloat: TPanel;
    pnlScanOptions: TPanel;
    pnlScanValueOptions: TPanel;
    pmTablist: TPopupMenu;
    pmValueType: TPopupMenu;
    pmResetRange: TPopupMenu;
    pmScanRegion: TPopupMenu;
    rbBit: TRadioButton;
    rbDec: TRadioButton;
    rbFsmAligned: TRadioButton;
    rbfsmLastDigts: TRadioButton;
    rt1: TRadioButton;
    rt2: TRadioButton;
    rt3: TRadioButton;
    SettingsButton: TSpeedButton;
    tbSpeed: TTrackBar;
    UpdateTimer: TTimer;
    FreezeTimer: TTimer;
    PopupMenu2: TPopupMenu;
    Deletethisrecord1: TMenuItem;
    Browsethismemoryregion1: TMenuItem;
    Calculatenewvaluepart21: TMenuItem;
    Freezealladdresses2: TMenuItem;
    sep1: TMenuItem;
    N1: TMenuItem;
    N4: TMenuItem;
    Copy1: TMenuItem;
    Paste1: TMenuItem;
    Cut1: TMenuItem;
    Setbreakpoint1: TMenuItem;
    SetHotkey1: TMenuItem;
    N5: TMenuItem;
    Panel4: TPanel;
    advancedbutton: TSpeedButton;
    CommentButton: TSpeedButton;
    Panel5: TPanel;
    ProcessLabel: TLabel;
    foundcountlabel: TLabel;
    ScanText: TLabel;
    lblScanType: TLabel;
    lblValueType: TLabel;
    LoadButton: TSpeedButton;
    SaveButton: TSpeedButton;
    Label6: TLabel;
    SpeedButton2: TSpeedButton;
    SpeedButton3: TSpeedButton;
    gbScanOptions: TGroupBox;
    btnNewScan: TButton;
    btnNextScan: TButton;
    ScanType: TComboBox;
    VarType: TComboBox;
    ProgressBar: TProgressBar;
    UndoScan: TButton;
    scanvalue: TEdit;
    foundlistpopup: TPopupMenu;
    Browsethismemoryarrea1: TMenuItem;
    Removeselectedaddresses1: TMenuItem;
    Selectallitems1: TMenuItem;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    TopDisabler: TTimer;
    emptypopup: TPopupMenu;
    ccpmenu: TPopupMenu;
    Cut2: TMenuItem;
    Copy2: TMenuItem;
    Paste2: TMenuItem;
    Splitter1: TSplitter;
    Findoutwhataccessesthisaddress1: TMenuItem;
    Showashexadecimal1: TMenuItem;
    Panel7: TPanel;
    sbOpenProcess: TSpeedButton;
    Change1: TMenuItem;
    Description1: TMenuItem;
    Address1: TMenuItem;
    Type1: TMenuItem;
    Value1: TMenuItem;
    Changescript1: TMenuItem;
    ActionList1: TActionList;
    actSave: TAction;
    actOpen: TAction;
    actAutoAssemble: TAction;
    Forcerechecksymbols1: TMenuItem;
    Smarteditaddresses1: TMenuItem;
    Pointerscanforthisaddress1: TMenuItem;
    Plugins1: TMenuItem;
    UpdateFoundlisttimer: TTimer;
    Browsethismemoryregioninthedisassembler1: TMenuItem;
    AutoAttachTimer: TTimer;
    btnFirst: TButton;
    btnNext: TButton;
    LogoPanel: TPanel;
    Logo: TImage;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Process1: TMenuItem;
    miHelp: TMenuItem;
    Edit3: TMenuItem;
    miAbout: TMenuItem;
    OpenProcess1: TMenuItem;
    Save1: TMenuItem;
    Load1: TMenuItem;
    Settings1: TMenuItem;
    N6: TMenuItem;
    a1: TMenuItem;
    b1: TMenuItem;
    c1: TMenuItem;
    d1: TMenuItem;
    e1: TMenuItem;
    CreateProcess1: TMenuItem;
    New1: TMenuItem;
    N7: TMenuItem;
    ools1: TMenuItem;
    N8: TMenuItem;
    Helpindex1: TMenuItem;
    Plugins2: TMenuItem;
    actMemoryView: TAction;
    actOpenProcesslist: TAction;
    procedure actOpenDissectStructureExecute(Sender: TObject);
    procedure actOpenLuaEngineExecute(Sender: TObject);
    procedure Address1Click(Sender: TObject);
    procedure cbCompareToSavedScanChange(Sender: TObject);
    procedure cbLuaFormulaChange(Sender: TObject);
    procedure cbPercentageOnChange(Sender: TObject);
    procedure cbCodePageChange(Sender: TObject);
    procedure cbRepeatUntilStoppedChange(Sender: TObject);
    procedure cbUnicodeChange(Sender: TObject);
    procedure Copyselectedaddresses1Click(Sender: TObject);
    procedure EnableLCLClick(Sender: TObject);
    procedure cbFastScanChange(Sender: TObject);
    procedure Description1Click(Sender: TObject);
    procedure edtAlignmentKeyPress(Sender: TObject; var Key: char);
    procedure FormDropFiles(Sender: TObject; const FileNames: array of string);
    procedure Foundlist3ColumnClick(Sender: TObject; Column: TListColumn);
    procedure Foundlist3CustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; var DefaultDraw: boolean);
    procedure Foundlist3CustomDrawSubItem(Sender: TCustomListView;
      Item: TListItem; SubItem: Integer; State: TCustomDrawState;
      var DefaultDraw: Boolean);
    procedure CreateGroupClick(Sender: TObject);
    procedure gbScanOptionsChangeBounds(Sender: TObject);
    procedure Label3Click(Sender: TObject);
    procedure miTestAccessViolationThreadClick(Sender: TObject);
    procedure miTriggerAccessViolationClick(Sender: TObject);
    procedure miTutorial64Click(Sender: TObject);
    procedure MenuItem15Click(Sender: TObject);
    procedure MenuItem16Click(Sender: TObject);
    procedure miClearWorkingSetClick(Sender: TObject);
    procedure miDeleteSavedScanResultsClick(Sender: TObject);
    procedure miFoundListPreferencesClick(Sender: TObject);
    procedure miAutoAssembleErrorMessageClick(Sender: TObject);
    procedure miHelpClick(Sender: TObject);
    procedure miLuaDocumentationClick(Sender: TObject);
    procedure miForgotScanClick(Sender: TObject);
    procedure miGetDotNetObjectListClick(Sender: TObject);
    procedure miChangeValueBackClick(Sender: TObject);
    procedure miDBVMFindWhatWritesOrAccessesClick(Sender: TObject);
    procedure miAlwaysHideChildrenClick(Sender: TObject);
    procedure miNetworkClick(Sender: TObject);
    procedure miNetworkReadUseProcMemClick(Sender: TObject);
    procedure miOnlyShowCurrentCompareToColumnClick(Sender: TObject);
    procedure miSignTableClick(Sender: TObject);
    procedure miAsyncScriptClick(Sender: TObject);
    procedure miFlFindWhatAccessesClick(Sender: TObject);
    procedure miBindDeactivationClick(Sender: TObject);
    procedure miDisassembleClick(Sender: TObject);
    procedure miFlFindWhatWritesClick(Sender: TObject);
    procedure miSaveFileClick(Sender: TObject);
    procedure miScanDirtyOnlyClick(Sender: TObject);
    procedure miCompressionClick(Sender: TObject);
    procedure miGeneratePointermapClick(Sender: TObject);
    procedure miManualExpandCollapseClick(Sender: TObject);
    procedure miSaveClick(Sender: TObject);
    procedure mi3dClick(Sender: TObject);
    procedure miChangeDisplayTypeClick(Sender: TObject);
    procedure miOpenFileClick(Sender: TObject);
    procedure miScanPagedOnlyClick(Sender: TObject);
    procedure miSetDropdownOptionsClick(Sender: TObject);
    procedure miShowAsSignedClick(Sender: TObject);
    procedure miShowCustomTypeDebugClick(Sender: TObject);
    procedure miShowPreviousValueClick(Sender: TObject);
    procedure miSnapshothandlerClick(Sender: TObject);
    procedure miTutorialClick(Sender: TObject);
    procedure miChangeValueClick(Sender: TObject);
    procedure MenuItem1Click(Sender: TObject);
    procedure miShowLuaScriptClick(Sender: TObject);
    procedure miAddAddressClick(Sender: TObject);
    procedure miAllowCollapseClick(Sender: TObject);
    procedure miHookD3DClick(Sender: TObject);
    procedure miLockMouseInGameClick(Sender: TObject);
    procedure miPresetAllClick(Sender: TObject);
    procedure miAddFileClick(Sender: TObject);
    procedure MenuItem9Click(Sender: TObject);
    procedure miPresetWritableClick(Sender: TObject);
    procedure miResyncFormsWithLuaClick(Sender: TObject);
    procedure miCreateLuaFormClick(Sender: TObject);
    procedure MenuItem7Click(Sender: TObject);
    procedure miSetCrosshairClick(Sender: TObject);
    procedure miTableClick(Sender: TObject);
    procedure miResetRangeClick(Sender: TObject);
    procedure miChangeColorClick(Sender: TObject);
    procedure miDefineNewCustomTypeLuaClick(Sender: TObject);
    procedure miDeleteCustomTypeClick(Sender: TObject);
    procedure miBindActivationClick(Sender: TObject);
    procedure miEditCustomTypeClick(Sender: TObject);
    procedure miHideChildrenClick(Sender: TObject);
    procedure miDefineNewCustomTypeClick(Sender: TObject);
    procedure miRecursiveSetValueClick(Sender: TObject);
    procedure miRenameTabClick(Sender: TObject);
    procedure miAddTabClick(Sender: TObject);
    procedure miCloseTabClick(Sender: TObject);
    procedure miFreezeNegativeClick(Sender: TObject);
    procedure miFreezePositiveClick(Sender: TObject);
    procedure miSaveScanresultsClick(Sender: TObject);
    procedure miShowAsBinaryClick(Sender: TObject);
    procedure miUndoValueClick(Sender: TObject);
    procedure miWireframeClick(Sender: TObject);
    procedure miZbufferClick(Sender: TObject);
    procedure miZeroTerminateClick(Sender: TObject);
    procedure Panel5Resize(Sender: TObject);
    procedure pmTablistPopup(Sender: TObject);
    procedure pmValueTypePopup(Sender: TObject);
    procedure rbFsmAlignedChange(Sender: TObject);
    procedure rtChange(Sender: TObject);
    procedure Save1Click(Sender: TObject);
    procedure ShowProcessListButtonClick(Sender: TObject);
    procedure btnNewScanClick(Sender: TObject);
    procedure btnNextScanClick(Sender: TObject);
    procedure btnMemoryViewClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure AddressKeyPress(Sender: TObject; var Key: char);
    procedure FoundListDblClick(Sender: TObject);
    procedure Browsethismemoryarrea1Click(Sender: TObject);
    procedure tLuaGCActiveTimer(Sender: TObject);
    procedure tLuaGCPassiveTimer(Sender: TObject);
    procedure UpdateTimerTimer(Sender: TObject);
    procedure FreezeTimerTimer(Sender: TObject);
    procedure Browsethismemoryregion1Click(Sender: TObject);
    procedure Deletethisrecord1Click(Sender: TObject);
    procedure ScanvalueoldKeyPress(Sender: TObject; var Key: char);
    procedure Calculatenewvaluepart21Click(Sender: TObject);
    procedure btnAddAddressManuallyClick(Sender: TObject);
    procedure ScanTypeChange(Sender: TObject);
    procedure Value1Click(Sender: TObject);
    procedure VarTypeChange(Sender: TObject);
    procedure LogoClick(Sender: TObject);
    procedure VarTypeDropDown(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
    procedure SpeedButton2Click(Sender: TObject);
    procedure SpeedButton3Click(Sender: TObject);
    procedure Selectallitems1Click(Sender: TObject);
    procedure Freezealladdresses2Click(Sender: TObject);
    procedure PopupMenu2Popup(Sender: TObject);
    procedure foundlistpopupPopup(Sender: TObject);
    procedure Removeselectedaddresses1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var cAction: TCloseAction);
    procedure CommentButtonClick(Sender: TObject);
    procedure Copy1Click(Sender: TObject);
    procedure Cut1Click(Sender: TObject);
    procedure Paste1Click(Sender: TObject);
    procedure Setbreakpoint1Click(Sender: TObject);
    procedure TopDisablerTimer(Sender: TObject);
    procedure advancedbuttonClick(Sender: TObject);
    procedure cbHexadecimalClick(Sender: TObject);
    procedure SetHotkey1Click(Sender: TObject);
    procedure UndoScanClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure rbBitClick(Sender: TObject);
    procedure rbDecClick(Sender: TObject);
    procedure Cut2Click(Sender: TObject);
    procedure Copy2Click(Sender: TObject);
    procedure Paste2Click(Sender: TObject);
    procedure ccpmenuPopup(Sender: TObject);
    procedure Splitter1Moved(Sender: TObject);
    procedure SettingsClick(Sender: TObject);
    procedure cbCaseSensitiveClick(Sender: TObject);
    procedure LogoMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: integer);
    procedure Findoutwhataccessesthisaddress1Click(Sender: TObject);
    procedure OpenProcesslist1Click(Sender: TObject);
    procedure CloseCheatEngine1Click(Sender: TObject);
    procedure Showashexadecimal1Click(Sender: TObject);
    procedure OpenMemorybrowser1Click(Sender: TObject);
    procedure cbPauseWhileScanningClick(Sender: TObject);
    procedure ProcessLabelDblClick(Sender: TObject);
    procedure ProcessLabelMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: integer);
    procedure cbUnrandomizerClick(Sender: TObject);
    procedure cbUnrandomizerMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: integer);
    procedure actOpenExecute(Sender: TObject);
    procedure actSaveExecute(Sender: TObject);
    procedure actAutoAssembleExecute(Sender: TObject);
    procedure Changescript1Click(Sender: TObject);
    procedure Forcerechecksymbols1Click(Sender: TObject);
    procedure Smarteditaddresses1Click(Sender: TObject);
    procedure Pointerscanforthisaddress1Click(Sender: TObject);
    procedure Foundlist3Data(Sender: TObject; Item: TListItem);
    procedure UpdateFoundlisttimerTimer(Sender: TObject);
    procedure Foundlist3KeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
    procedure Browsethismemoryregioninthedisassembler1Click(Sender: TObject);
    procedure AutoAttachTimerTimer(Sender: TObject);
    procedure btnFirstClick(Sender: TObject);
    procedure btnNextClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure tbSpeedChange(Sender: TObject);
    procedure btnSetSpeedhack2Click(Sender: TObject);
    procedure cbSpeedhackChange(Sender: TObject);
    procedure Process1Click(Sender: TObject);
    procedure miAboutClick(Sender: TObject);
    procedure CreateProcess1Click(Sender: TObject);
    procedure Helpindex1Click(Sender: TObject);
    procedure New1Click(Sender: TObject);
    procedure File1Click(Sender: TObject);
    procedure actOpenProcesslistExecute(Sender: TObject);
    procedure Type1Click(Sender: TObject);
  private
    repeatscantimer: TTimer;
    onetimeonly: boolean; //to protect against make mainform visible (.show)

    scantimestart, scantimefinish: int64;

    tabcounter: integer;
    //variable that only goes up, doesn't go down when a tab is deleted
    scantablist: TTablist;

    oldscanvalue2text: string;
    aaa: single;
    hotkeypressed: integer;

    cancelbutton: TButton;
    //cancel button that spawns during a scan, disabled initially to prevent doubleclick accidents
    cancelbuttonenabler: TTimer;
    //timer that will enable the cancelbutton after 3 seconds

    groupconfigbutton: TButton;

    oldwidth, oldheight: integer;
    newaddress: ptrUint;
    isbit: boolean;
    tempbitmap: Tbitmap;
    dontrunshow: boolean;

    LastWasHex: boolean;
    dontconvert: boolean;
    FlashProcessButton: TFlash;
    oldvartype: integer;

    unrandomize: Tunrandomize;



    reinterpretcheck: integer;

    ffoundcount: int64;
    foundlistDisplayOverride: integer; //a number specifying what type to display (0=default)

    SaveFirstScanThread: TSaveFirstScanThread;

    foundlist: Tfoundlist;

    compareToSavedScan: boolean;
    fActivePreviousResultColumn: integer; //the column index which is going to be compared against
    currentlySelectedSavedResultname: string; //I love long variable names

    PreviousResultList: Tlist;



    lastscantype: integer;
    oldhandle: thandle;

    alignsizechangedbyuser: boolean;
    scantypechangedbyhotkey: boolean;

    fIsProtected: boolean;
    fOnProcessOpened: TProcessOpenedEvent;

    overlayid: integer;   //debug
    lastAdded: record
      Address: string;
      vartype: TVariableType;
      customTypeName: string;
    end;

    foundlistColors: record
      NormalValueColor: TColor;
      ChangedValueColor: TColor;
      StaticColor: TColor;
      DynamicColor: TColor;
      CompareToHeaderColor: TColor;
    end;


    saveGotCanceled: boolean; //set to true if the last save button click was canceled

    UserDefinedTableName: string; //set when a user opens a table (when set the filename prediction will be turned off)

    speedhackDisableTimer: TTimer;
    boundsupdater: TTimer;

    freezeThread: TFreezeThread;

    showStaticAsStatic: boolean;
    AddressListOverrideFontSize: boolean;

    RecentFiles: Tstringlist;

    InsideSetActivePreviousResult: boolean;

    exceptionerrorcs: TCriticalSection;
    currentexceptionerror: string;
    showingException: boolean;

    TraceExceptions: boolean;

    procedure updateNetworkOption(sender: TObject);
    procedure updateNetworkOptions;

    procedure ClearRecentFiles(Sender:TObject);
    procedure RecentFilesClick(Sender:TObject);
    procedure CheckForSpeedhackKey(sender: TObject);

    procedure doNewScan;
    procedure SetExpectedTableName;

    function CheckIfSaved: boolean;
    procedure checkpaste;
    procedure hotkey(var Message: TMessage); {$ifdef windows}message WM_HOTKEY;{$endif}

    procedure MemScanStart(sender: TObject);
    procedure MemScanDone(sender: TObject);
    procedure PluginSync(var m: TMessage); message wm_pluginsync;
    procedure ShowError;
    procedure Edit;
    procedure paste(simplecopypaste: boolean);
    procedure CopySelectedRecords;


    procedure exceptionhandler(Sender: TObject; E: Exception);
    procedure toggleWindow;
    procedure adjustbringtofronttext;

    procedure scanEpilogue(canceled: boolean);
    procedure CancelbuttonClick(Sender: TObject);
    procedure CancelbuttonenablerInterval(Sender: TObject);
    procedure repeatScanTimerTimer(sender: TObject);

    procedure changeScriptCallback(memrec: TMemoryRecord; script: string; scriptchanged: boolean);

    //processlist
    procedure ProcessItemClick(Sender: TObject);

    //property functions
    function GetRoundingType: TRoundingType;
    procedure SetRoundingType(rt: TRoundingType);
    function getScanStart: ptruint;
    procedure setScanStart(newscanstart: ptruint);
    function getScanStop: ptruint;
    procedure setScanStop(newscanstop: ptruint);
    function getFastscan: boolean;
    procedure setFastScan(state: boolean);

    function getSelectedVariableType: TVariableType;
    procedure setfoundcount(x: int64);


    procedure AddresslistDropByListview(Sender: TObject; node: TTreenode;
      attachmode: TNodeAttachMode);

    procedure SaveCurrentState(scanstate: PScanState; skipuservalues: boolean=false);
    procedure SetupInitialScanTabState(scanstate: PScanState; IsFirstEntry: boolean);
    procedure ScanTabListTabChange(Sender: TObject; oldselection: integer);

    procedure UpdateFloatRelatedPositions;

    //custom type:
    procedure CreateCustomType(customtype: TCustomtype; script: string;
      scriptchanged: boolean; lua: boolean = False);


    procedure LoadCustomTypesFromRegistry;

    procedure setGbScanOptionsEnabled(state: boolean);
    procedure cbSaferPhysicalMemoryChange(sender: tobject);


    function onhelp(Command: word; Data: PtrInt; var CallHelp: boolean): boolean;
    procedure SaveIntialTablesDir(dir: string);

    function convertvalue(ovartype, nvartype: integer; oldvalue: string;
      washexadecimal, ishexadecimal: boolean): string;

    //designer functions
    procedure RenameFileClick(Sender: TObject);
    procedure SaveFileClick(Sender: TObject);
    procedure DeleteFileClick(Sender: TObject);

    procedure EditFormClick(Sender: TObject);
    procedure RestoreAndShowFormClick(Sender: TObject);
    procedure DeleteFormClick(Sender: TObject);
    procedure FormDesignerClose(Sender: TObject; var CloseAction: TCloseAction);

    procedure setIsProtected(p: boolean);

    procedure d3dclicktest(_overlayid: integer; x, y: integer);


    procedure createGroupConfigButton;
    procedure destroyGroupConfigButton;

    procedure BoundsUpdate(sender: TObject);
    procedure SpawnBoundsUpdater;

    procedure MemscanGuiUpdate(sender: TObject; totaladdressestoscan: qword; currentlyscanned: qword; foundcount: qword);

    function getUseThreadToFreeze: boolean;
    procedure setUseThreadToFreeze(state: boolean);

    procedure recentFilesUpdate(filepath: string);

    procedure reloadPreviousResults;
    procedure cleanupPreviousResults;
  public
    { Public declarations }
    addresslist: TAddresslist;

    //test: single;
    itemshavechanged: boolean;

    debugproc: boolean;
    autoopen: boolean;
    //boolean set when table is opened by other means than user file picker

    Priority: Dword;
    memimage: TMemorystream;

    canceled: boolean;

    originalheight: integer;
    originalwidth: integer;

    fronttext: string;



    editedsincelastsave: boolean;

    autoattachlist: TStringList;
    extraautoattachlist: TStringList;
    //modifed by plugins and scripts, not affected by settings changes
    oldcodelistcount: integer;

    memscan: tmemscan;
    LuaForms: TList;
    LuaFiles: TLuaFileList;
    InternalLuaFiles: TLuaFileList;
    frmLuaTableScript: Tfrmautoinject;


    cbsaferPhysicalMemory: TCheckbox;
    mustClose: boolean;

    imgSignature: TImage;



    {$ifdef darwin}
    cbDirty: TCheckbox;
    {$endif}

    procedure setActivePreviousResultColumn(c: integer);
    procedure Hotkey2(command: integer);


    procedure updated3dgui;
    procedure RefreshCustomTypes;

    procedure autoattachcheck(pl: TStringList = nil); // can be called by AutoAttachTimer or AutoAttachThread
    function openprocessPrologue: boolean;
    procedure openProcessEpilogue(oldprocessname: string; oldprocess: dword;
      oldprocesshandle: dword; autoattachopen: boolean = False);


    procedure ChangedHandle(Sender: TObject);
    procedure plugintype0click(Sender: TObject);
    procedure plugintype5click(Sender: TObject);
    procedure OnToolsClick(Sender: TObject);
    procedure AddToRecord(Line: integer; node: TTreenode = nil;
      attachmode: TNodeAttachMode = naAdd);
    procedure AddAutoAssembleScript(script: string);
    procedure reinterpretaddresses;


    procedure ClearList;

    procedure CreateScanValue2;
    procedure DestroyScanValue2;


    procedure CreateCbPercentage;
    procedure DestroyCbPercentage;

    procedure UpdateScanType;
    procedure enableGui(isnextscan: boolean);
    procedure disableGui;
    procedure SpawnCancelButton;
    procedure DestroyCancelButton;

    function AddressListAutoAssemblerEdit(Sender: TObject; memrec: TMemoryRecord): boolean;
    procedure createFormdesigner;
    procedure UpdateMenu;

    procedure DoGroupconfigButtonClick(sender: tobject);

    function getVarType: TVariableType;
    function getVarType2: TVariableType;
    procedure setVarType(vt: TVariableType);

    function GetScanType: TScanOption;
    function GetScanType2: TScanOption;

    procedure DBVMFindWhatWritesOrAccesses(address: ptruint);


    property foundcount: int64 read ffoundcount write setfoundcount;
    property RoundingType: TRoundingType read GetRoundingType write SetRoundingType;
    property ScanStart: ptruint read getScanStart write setScanStart;
    property ScanStop: ptruint read getScanStop write setScanStop;
    property FastScan: boolean read getFastscan write setFastscan;


    property SelectedVariableType: TVariableType read getSelectedVariableType;
    property isProtected: boolean read fIsProtected write setIsProtected;

    property ActivePreviousResultColumn: integer read fActivePreviousResultColumn write setActivePreviousResultColumn;
  published
    property Progressbar1: TProgressBar read Progressbar write ProgressBar;
    property About1: TMenuItem read miAbout write miAbout;
    property Help1: TMenuItem read miHelp write miHelp;
    property OnProcessOpened: TProcessOpenedEvent read fOnProcessOpened write fOnProcessOpened;
    property UseThreadToFreeze: boolean read getUseThreadToFreeze write setUseThreadToFreeze;
  end;

var
  MainForm: TMainForm;
  ToggleWindows: TTogglewindows;
  AutoAttachThread: TAutoAttachThread;

resourcestring
  strPhysicalMemory = 'Physical Memory';

implementation


uses cefuncproc, MainUnit2, ProcessWindowUnit, MemoryBrowserFormUnit, TypePopup, HotKeys,
  aboutunit, formhotkeyunit, formDifferentBitSizeUnit,
  CommentsUnit, formsettingsunit, formAddressChangeUnit, Changeoffsetunit,
  FoundCodeUnit, AdvancedOptionsUnit, frmProcessWatcherUnit,
  formPointerOrPointeeUnit, OpenSave, formmemoryregionsunit, formProcessInfo,
  PasteTableentryFRM, pointerscannerfrm, PointerscannerSettingsFrm,
  frmFloatingPointPanelUnit, pluginexports {$ifdef windows},DBK32functions, frmUltimapUnit,
  frmSetCrosshairUnit{$endif},StructuresFrm2 {$ifdef windows} ,frmMemoryViewExUnit,
  frmD3DHookSnapshotConfigUnit,frmSaveSnapshotsUnit, frmsnapshothandlerUnit,
  frmNetworkDataCompressionUnit{$endif},ProcessHandlerUnit, processlist, pointeraddresslist,
  PointerscanresultReader, Parsers, Globals {$ifdef windows},GnuAssembler, xinput{$endif} ,DPIHelper,
  multilineinputqueryunit {$ifdef windows},winsapi{$endif} ,LuaClass, Filehandler{$ifdef windows}, feces{$endif}
  {$ifdef windows},frmDBVMWatchConfigUnit, frmDotNetObjectListUnit{$endif} ,ceregistry ,UnexpectedExceptionsHelper
  ,frmFoundlistPreferencesUnit, fontSaveLoadRegistry{$ifdef windows}, cheatecoins{$endif},strutils, iptlogdisplay,
  libcepack, symbolsync;

resourcestring
  rsInvalidStartAddress = 'Invalid start address: %s';
  rsInvalidStopAddress = 'Invalid stop address: %s';
  rsThisButtonWillTryToCancelTheCurrentScanClickTwiceT =
    'This button will try to cancel the current scan. Click twice to force an exit';
  rsCancel = 'Cancel';
  strWindowFailedToHide = 'A window failed to hide';
  strAccessed = 'The following opcodes accessed the selected address';
  strOpcodeRead = 'The following opcodes read from the selected address';
  strOpcodeChanged = 'The following opcodes changed the selected address';
  strAskToSave = 'You haven''t saved your last changes yet. Save Now?';
  strScantextcaptiontotext = 'Text:';
  strScantextcaptiontoValue = 'Value:';
  strsearchForText = 'Search for text';
  strSearchForArray = 'Search for this array';
  rsValue = 'Value %';
  rsBetween = 'between %';
  rsAtLeastXx = 'at least xx%';
  rsAnd = 'and';
  strConfirmProcessTermination =
    'This will close the current process. Are you sure you want to do this?';
  strError = 'Error';
  strErrorwhileOpeningProcess = 'Error while opening this process';
  strErrorWhileOpeningProcessMac = '. Have you disabled ''System Integrity Protection''(SIP) yet?';
  strKeepList = 'Keep the current address list/code list?';
  strInfoAboutTable = 'Info about this table:';

  strSaferPhysicalMemory = 'Safer memory access';
  rsThereAreOneOrMoreAutoAssemblerEntriesOrCodeChanges =
    'There are one or more auto assembler entries or code changes enabled in this table. Do you want them disabled? (without '
    + 'executing the disable part)';
  rsLoadTheAssociatedTable = 'Load the associated table? (%s)';
  rsGroup = 'Group %s';
  rsGroups = 'Groups';
  rsWhatDoYouWantTheGroupnameToBe = 'What do you want the groupname to be?';
  rsDoYouWantTheGroupWithAddress = 'Do you want a header with address support ?';
  rsAreYouSureYouWantToDeleteThisForm = 'Are you sure you want to delete this form?';
  rsRenameFile = 'Rename file';
  rsGiveTheNewFilename = 'Give the new filename';
  rsRestoreAndShow = 'Restore and show';
  rsEdit = 'Edit';
  rsDelete = 'Delete';
  rsRename = 'Rename';
  rsSaveToDisk = 'Save to disk';
  rsAreYouSureYouWantToDelete = 'Are you sure you want to delete %s?';
  rsWhatWillBeTheNewNameForThisTab = 'What will be the new name for this tab?';
  rsScan = 'Scan';
  rsScanresult = 'Scanresult';
  rsSaveScanResults = 'Save scan results';
  rsWhatNameDoYouWantToGiveToTheseScanresults =
    'What name do you want to give to these scanresults?';
  strClickToGoHome = 'Click here to go to the '+strCheatEngine+' homepage';
  rsLuaScriptCheatTable = 'Lua script: '+strCheatTable;
  strChangeDescription1 = 'Description';
  strChangeDescription2 = 'Change the description to:';

  strNotTheSameSize1 = 'The text you entered isn''t the same size as the original. Continue?';
  strNotTheSameSize2 = 'Not the same size!';
  strAdd0 = 'Do you want to add a ''0''-terminator at the end?';
  strNotAValidNotation = 'This is not a valid notation';
  strNotSameAmmountofBytes =
    'The number of bytes you typed is not the same as the previous ammount. Continue?';
  strNotAValidBinaryNotation = ' is not a valid binary notation!';

  strValue = 'Value';
  strChange1Value = 'Change this value to:';
  strChangeMoreValues = 'Change these values to:';

  strSelectedAddressIsAPointer =
    'The selected address is a pointer. Are you sure? (the base pointer will get the address)';
  strMorePointers = 'There are more pointers selected. Do you want to change them as well?';
  strMorePointers2 =
    'You have selected one or more pointers. Do you want to change them as well?';
  strNotAValidValue = 'This is not an valid value';
  rsTheRecordWithDescriptionHasAsInterpretableAddressT =
    'The record with description ''%s'' has as interpretable address ''%s''. The recalculation will change it to %s. Do you '
    + 'want to edit it to the new address?';
  rsSavedScanResults = 'Saved scan results';
  rsSelectTheSavedScanResultFromTheListBelow =
    'Select the saved scan result from the list below';
  rsSelectTheSavedScanResultToDeleteFromTheListBelow =
    'Select the saved scan result to delete from the list below';
  rsComparingTo = 'Comparing to %s';
  rsHex = 'Hex';
  rsDoYouWantToGoToTheCheatEngineWebsite =
    'Do you want to go to the '+strCheatEngine+' website?';

  strdeleteall = 'Are you sure you want to delete all addresses?';
  stralreadyin = 'This address is already in the list';
  stralreadyinlistmultiple = 'One or more addresses where already in the list';
  strsethotkey = 'Set a hotkey';
  strshowasdecimal = 'Show as decimal value';
  strshowashex = 'Show as hexadecimal value';
  strFreezeAddressInList = 'Freeze the address in this list';
  strFreezeAllAddresses = 'Freeze all addresses in this list';
  strUnfreezeAllAddresses = 'Unfreeze all addresses in this list';
  strUnfreezeAddressInList = 'Unfreeze the address in this list';
  strDeleteAddress = 'Delete this address';
  strDeleteTheseAddresses = 'Delete these addresses';
  strRecalculateAddress = 'Recalculate address';
  strRecalculateSelectedAddresses = 'Recalculate selected addresses';
  strRecalculateAllAddresses = 'Recalculate all addresses';

  strRemoveFromGroup = 'Remove from group ';

  strChangeScript = 'Change script';
  strEnableCheat = 'Enable '+strCheat;
  strDisableCheat = 'Disable '+strCheat;

  strForceRecheck = 'Force recheck symbols';
  rsSetChangeHotkeys = 'Set/Change hotkeys';
  rsSetHotkeys = 'Set hotkeys';
  rsShowAsDecimal = 'Show as decimal';
  rsShowAsBinary = 'Show as binary';
  rsShowAsHexadecimal = 'Show as hexadecimal';
  rsRemoveSelectedAddresses = 'Remove selected addresses';
  rsRemoveSelectedAddress = 'Remove selected address';
  rsThisListIsHuge =
    'This list is huge and deleting multiple items will require CE to traverse the whole list and can take a while. Are you sure?';
  rsFindOutWhatAccessesThisPointer = 'Find out what accesses this pointer';
  rsFindWhatAccessesTheAddressPointedAtByThisPointer =
    'Find what accesses the address pointed at by this pointer';
  rsFindOutWhatWritesThisPointer = 'Find out what writes this pointer';
  rsFindWhatWritesTheAddressPointedAtByThisPointer =
    'Find what writes the address pointed at by this pointer';

  strconfirmUndo = 'Do you really want to go back to the results of the previous scan?';

  strHideForeground = 'will hide the foreground window';
  strHideAll = 'will hide all windows';
  strUnHideForeground = 'will bring the foreground window back';
  strUnhideAll = 'will bring all windows back';
  rsBringsCheatEngineToFront = 'brings '+strCheatEngine+' to front';

  strhappybirthday = 'Let''s sing Happy Birthday for Dark Byte today!';
  strXMess = 'Merry christmas and happy new year';
  strNewyear = 'And what are your good intentions for this year? ;-)';
  strfuture = 'Wow,I never imagined people would use '+strCheatEngine+' up to today';
  rsEXPIRED = 'EXPIRED';
  strdontbother =
    'Don''t even bother. '+strCheatEngine+' uses the main thread to receive messages when the scan is done, freeze it and CE will crash!';
  rsTheProcessIsnTFullyOpenedIndicatingAInvalidProcess =
    'The process isn''t fully opened. Indicating a invalid ProcessID. You still want to find out the EPROCESS? (BSOD is '
    + 'possible)';
  rsUnrandomizerInfo =
    'This will scan for and change some routines that are commonly used to generate a random value so they always return the same. Please be aware that there ' + 'is a chance it overwrites the wrong routines causing the program to crash, or that the program uses an unknown random generator. Continue?';

  strUnknownExtension = 'Unknown extension';
  rsDoYouWishToMergeTheCurrentTableWithThisTable =
    'Do you wish to merge the current table with this table?';
  rsDoYouWantToProtectThisTrainerFileFromEditing =
    'Do you want to protect this trainer file from editing?';
  rsAutoAssembleEdit = 'Auto Assemble edit: %s';
  rsEditAddresses = 'Edit addresses';
  rsScanError = 'Scan error:%s';
  rsShown = 'shown';
  rsTerminatingScan = 'Terminating scan...';
  rsThisButtonWillForceCancelAScanExpectMemoryLeaks =
    'This button will force cancel a scan. Expect memory leaks';
  rsForceTermination = 'Force termination';
  rsYouAreLowOnDiskspaceOnTheFolderWhereTheScanresults =
    'You are low on diskspace on the folder where the scanresults are stored. Scanning might fail. Are you sure you want to '
    + 'continue?';
  rsIsNotAValidSpeed = '%s is not a valid speed';
  rsAreYouSureYouWantToEraseTheDataInTheCurrentTable =
    'Are you sure you want to erase the data in the current table?';


  rsSaved = 'Saved';
  rsPrevious = 'Previous';

  rsDecimal = 'Decimal';
  rsHexadecimal = 'Hexadecimal';
  rsIsNotAValidX = '%s is not a valid xml name';
  rsMUGenerateGroupscanCommand = 'Generate groupscan command';
  rsTryTutorial = 'Do you want to try out the tutorial?';
  rsUnspecifiedError = 'Unspecified error';
  rsGroupscanDataInvalid = 'groupscan data invalid';
  rsGroupscanResultWithNoGroupscanparser = 'Groupscan result with no groupscanparser';
  rsFailedToLoad = 'failed to load';
  rsFailureSettingTheDebugPrivilege = 'Failure setting the debug privilege. Debugging may be limited.';
  rsFailureSettingTheSeTcbPrivilegePrivilege = 'Failure setting the SeTcbPrivilege privilege. Debugging may be limited.';
  rsFailureSettingTheLoadDriverPrivilege = 'Failure setting the load driver privilege. Debugging may be limited.';
  rsFailureSettingTheCreateGlobalPrivilege = 'Failure setting the CreateGlobal privilege.';
  rsCurrentProcess = 'Current process';
  rsBusy = '<busy>';
  rsFileInUse = '<File in use>';
  rsPleaseWait = '<Processing>';
  rsCEError = 'CE Error:';
  rsPart = ' part ';
  rsChangeValue = 'Change value';
  rsGiveTheNewValueForTheSelectedAddressEs = 'Give the new value for the selected address(es)';
  rsOverlay = 'overlay ';
  rsWasClickedAtPositon = ' was clicked at positon ';
  rsWidth = '   -   width=';
  rsHeight = ' , height=';
  rsUnableToScanFixYourScanSettings = 'Unable to scan. Fix your scan settings and restart '+strCheatEngine;
  rsCustomLuaType = 'Custom LUA type';
  rsCustomTypeName = 'Custom Type Name';
  rsLanguage = 'Language';
  rsChooseLanguage = 'Which language do you wish to use?';
  rsInvalidScanFolder = '%s is not accessible like it should.  Please '
    +'configure a proper location in the settings';
  rsProcessing = '<Processing>';
  rsCompareToSavedScan = 'Compare to first/saved scan';
  rsModified = 'Modified';
  rsRequiresDBVMCapableCPU = 'This function requires an CPU with '
    +'virtualization support. If your system has that then make sure that '
    +'you''re currently not running inside a virtual machine. (Windows has '
    +'some security features that can run programs inside a VM)';
  rsRequiresEPT = 'This function requires that your CPU supports ''Intel Extended '
    +'Page Table (EPT) or AMD Nested Paging'' which your CPU lacks';
  rsRequiresDBVMEPT = 'DBVM find routines needs DBVM for EPT/NP page hooking. '
    +'Loading DBVM can potentially cause a system freeze. Are you sure?';
  rsDbvmWatchFailed = 'dbvm_watch failed';
  rsAreYouSure = 'Are you sure?';
  rsClearRecentFiles = 'Empty Recent Files List';
  rsFirst = 'First';
  rsEnableSpeedHack = 'Enable '+strSpeedHack;
  rsPreviousValueList = 'Previous value list';
  rsSelectTheSavedResult = 'Select the saved results you wish to use';
  rsNetworkOption = 'Network option :';
  rsClearingMeansSlowness = 'Clearing the assigned memory for this process '
    +'will cause it to obtain all the memory it needs again which can cause a '
    +'temporary slowdown in the target. Make sure the value you''re interested '
    +'in gets accessed once before you scan. Continue?';

const
  VARTYPE_INDEX_BINARY=0;
  VARTYPE_INDEX_BYTE=1;
  VARTYPE_INDEX_WORD=2;
  VARTYPE_INDEX_DWORD=3;
  VARTYPE_INDEX_QWORD=4;
  VARTYPE_INDEX_SINGLE=5;
  VARTYPE_INDEX_DOUBLE=6;
  VARTYPE_INDEX_TEXT=7;
  VARTYPE_INDEX_AOB=8;
  VARTYPE_INDEX_ALL=9;
  VARTYPE_INDEX_GROUPED=10;
  VARTYPE_INDEX_CUSTOMBASE=11;


var
  ncol: TColor;

procedure TFlash.Col;
begin
  if ncol=graphics.cldefault then
    mainform.panel7.Color:=mainform.Color
  else
    mainform.panel7.Color := ncol;
end;

procedure TFlash.Execute;
var
  red, green: byte;
  decreasered: boolean;
begin

{$ifndef ceasinjecteddll}
  decreasered := True;
  red := 254;
  green := 0;
  while not terminated do
  begin
    if decreasered then
    begin
      Dec(red, 2);
      Inc(green, 2);
      if green >= 250 then
        decreasered := False;
    end
    else
    begin
      Inc(red, 2);
      Dec(green, 2);
      if red >= 254 then
        decreasered := True;
    end;
    ncol := (green shl 8) + red;

    if not terminated then
      synchronize(@col);

    sleep(10);
  end;

{$endif}
  ncol := graphics.cldefault;
  synchronize(@col);
end;

constructor TToggleWindows.Create(CreateSuspended: boolean);
begin
  freeonterminate := True;
  inherited Create(CreateSuspended);
end;

procedure TToggleWindows.Execute;
begin
  toggleotherwindows;
  togglewindows := nil;
end;


//--------------TFreezeThread------------
procedure TFreezeThread.applyFreeze;
begin
  faddresslist.ApplyFreeze;
end;

procedure TFreezeThread.Execute;
begin
  while not terminated do
  begin
    synchronize(@applyFreeze); //has to be synchronized as the addreslist records are accessed by treenode indexes, which are GUI based
    sleep(freezeInterval);
  end;
end;

constructor TFreezeThread.Create(AddressList: TAddresslist; interval: integer);
begin
  fAddressList:=addressList;
  freezeInterval:=interval;
  inherited create(false);
end;

//--------------TMainThread------------

procedure TMainForm.recentFilesUpdate(filepath: string);
var i: integer;
begin
  i:=recentfiles.IndexOf(filepath);
  if i<>-1 then
  begin
    //move the old entry to the top
    recentfiles.Delete(i);
    recentfiles.Insert(0,filepath);
  end
  else
  begin
    //new entry
    recentfiles.insert(0, filepath);
    while recentfiles.count>20 do
      recentfiles.Delete(recentfiles.count-1);
  end;
  cereg.writeStrings('Recent Files', recentfiles);
end;

function TMainForm.getUseThreadToFreeze: boolean;
begin
  result:=freezeThread<>nil;
end;

procedure TMainForm.setUseThreadToFreeze(state: boolean);
begin
  if freezethread<>nil then
  begin
    if state then //update?
    begin
      if freezethread.freezeInterval<>freezetimer.interval then
        freezethread.freezeInterval:=freezetimer.interval;
    end
    else
      freeandnil(freezethread);
  end
  else
  begin
    if state then
      freezethread:=TFreezeThread.Create(addresslist,freezetimer.interval);
  end;



  freezetimer.enabled:=not state;
end;

procedure TMainForm.setIsProtected(p: boolean); //super unhackable protection yeeeeeh
//I'll sue you for DMCA violations if you edit this code!!!! Really! I mean it! I do!!!!
var
  i: integer;
begin
  fIsProtected := p;

  if p then
  begin

    //It's fucking time!!!!
    FreeAndNil(advancedoptions);
    FreeAndNil(actionlist1);

    for i := 0 to ControlCount - 1 do
      Controls[i].Visible := False;

    mainform.menu := nil;

    addresslist.PopupMenu := nil;
    addresslist.Enabled := False;

    Visible := False;

    miTable.Enabled := False;
    while miTable.Count > 0 do
      miTable.Delete(0);

    FreeAndNil(changescript1);

    frmLuaTableScript.assemblescreen.ClearAll;
    frmLuaTableScript.assemblescreen.Text:='wut?';
  end;
end;

procedure TMainForm.CheckForSpeedhackKey(sender: TObject);
var
  s: integer;
  down: boolean;
begin
//  if speed
  s:=ttimer(sender).tag;
  down:=false;

  case s of
    1: down:=CheckKeyCombo(speedhackspeed1.keycombo);
    2: down:=CheckKeyCombo(speedhackspeed2.keycombo);
    3: down:=CheckKeyCombo(speedhackspeed3.keycombo);
    4: down:=CheckKeyCombo(speedhackspeed4.keycombo);
    5: down:=CheckKeyCombo(speedhackspeed5.keycombo);
  end;

  if not down then
  begin
    editsh2.Text := '1';
    btnSetSpeedhack2.Click;
    ttimer(sender).enabled:=false;
  end;
end;

procedure TMainForm.Hotkey2(command: integer);
type
  PNotifyEvent = ^TNotifyEvent;
var
  i: integer;
  a, b: single;
  s: string;

  hk: TMemoryRecordHotkey;
  gh: TGenericHotkey;

  hOtherWin : THandle;
  OtherThreadID : DWORD;
  CurrentThreadID : DWORD;
  lockTimeOut: DWORD;
  pid: dword;
begin

    case command of
      0:
      begin
        {$ifdef windows}
        GetWindowThreadProcessId(GetForegroundWindow, pid);
        ce_openProcess(pid);
        {$endif}
      end;
      1:
      begin
        //popup/hide CE
        {$ifdef windows}
        if advancedoptions.Pausebutton.Down then
        begin
          errorbeep;
          exit;
        end;

        hOtherWin := GetForegroundWindow;
        GetWindowThreadProcessID( hOtherWin, OtherThreadID);
        CurrentThreadID := GetCurrentThreadID;

        if CurrentThreadID<>OtherThreadID then
        begin
          AttachThreadInput( CurrentThreadID, OtherThreadID, true );
          SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @lockTimeOut, 0);
          SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, 0);
          AllowSetForegroundWindow(ASFW_ANY);
        end;

        beep;

        if formsettings.frameHotkeyConfig.cbHideAllWindows.Checked then
        begin
          ToggleWindow;

          if formsettings.frameHotkeyConfig.cbCenterOnPopup.Checked then
            if not allwindowsareback then
              setwindowpos(mainform.Handle, HWND_NOTOPMOST, (screen.Width div 2) -
                (mainform.Width div 2), (screen.Height div 2) -
                (mainform.Height div 2), mainform.Width, mainform.Height,
                SWP_NOZORDER or SWP_NOACTIVATE);

          if not allwindowsareback then
          begin
            application.BringToFront;
            if CurrentThreadID<>OtherThreadID then
            begin
              SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, @lockTimeOut, 0);
              AttachThreadInput( CurrentThreadID, OtherThreadID, false );
            end;
          end
          else
            setforegroundwindow(lastforeground);

          adjustbringtofronttext;
          exit;
        end;

        application.BringToFront;
        SetForegroundWindow(mainform.Handle);

        mainform.SetFocus;

        if CurrentThreadID<>OtherThreadID then
        begin
          SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, @lockTimeOut, 0);
          AttachThreadInput( CurrentThreadID, OtherThreadID, false );
        end;

        if formsettings.frameHotkeyConfig.cbCenterOnPopup.Checked then
          setwindowpos(mainform.Handle, HWND_NOTOPMOST, (screen.Width div 2) -
            (mainform.Width div 2), (screen.Height div 2) -
            (mainform.Height div 2), mainform.Width, mainform.Height,
            SWP_NOZORDER or SWP_NOACTIVATE);

        formstyle := fsStayOnTop;
        {$endif}
      end;

      2: //Pause
      begin
        with advancedoptions do
        begin
          pausedbyhotkey := True;
          pausebutton.down := not pausebutton.down;
          pausebutton.Click;
          pausedbyhotkey := False;
        end;
      end;

      3: //speedhack
      begin
        if cbSpeedhack.Enabled then
        begin
          try
            cbSpeedhack.Checked := not cbSpeedhack.Checked;
            btnSetSpeedhack2.Click;
            beep;
          except
            errorbeep;
          end;
        end;
      end;

      //3..7=set speedhack speed
      4:
      begin
        if cbspeedhack.Enabled then
        begin
          try
            cbspeedhack.Checked := True;

            if cbspeedhack.Checked then
            begin
              editsh2.Text := format('%.3f', [speedhackspeed1.speed]);  //Just rebuild. I wish this would get fixed in fpc someday...
              btnSetSpeedhack2.Click;

              if speedhackspeed1.disablewhenreleased then
              begin
                //spawn a timer
                if speedhackDisableTimer=nil then
                begin
                  speedhackDisableTimer:=TTimer.create(self);
                  speedhackDisableTimer.OnTimer:=@CheckForSpeedhackKey;
                end;

                speedhackDisableTimer.Interval:=hotkeyPollInterval;
                speedhackDisableTimer.Tag:=1;
                speedhackDisableTimer.enabled:=true;
              end;

            end;
          except
            errorbeep;
          end;
        end;
      end;

      5:
      begin
        if cbspeedhack.Enabled then
        begin
          cbspeedhack.Checked := True;
          if cbspeedhack.Checked then
          begin
            editsh2.Text := format('%.3f', [speedhackspeed2.speed]);
            btnSetSpeedhack2.Click;

            if speedhackspeed2.disablewhenreleased then
            begin
              //spawn a timer
              if speedhackDisableTimer=nil then
              begin
                speedhackDisableTimer:=TTimer.create(self);
                speedhackDisableTimer.OnTimer:=@CheckForSpeedhackKey;
              end;

              speedhackDisableTimer.Interval:=hotkeyPollInterval;
              speedhackDisableTimer.Tag:=2;
              speedhackDisableTimer.enabled:=true;
            end;
          end;
        end;
      end;

      6:
      begin
        if cbspeedhack.Enabled then
        begin
          cbspeedhack.Checked := True;
          if cbspeedhack.Checked then
          begin
            editsh2.Text := format('%.3f', [speedhackspeed3.speed]);
            btnSetSpeedhack2.Click;

            if speedhackspeed3.disablewhenreleased then
            begin
              //spawn a timer
              if speedhackDisableTimer=nil then
              begin
                speedhackDisableTimer:=TTimer.create(self);
                speedhackDisableTimer.OnTimer:=@CheckForSpeedhackKey;
              end;

              speedhackDisableTimer.Interval:=hotkeyPollInterval;
              speedhackDisableTimer.Tag:=3;
              speedhackDisableTimer.enabled:=true;
            end;
          end;
        end;
      end;

      7:
      begin
        if cbspeedhack.Enabled then
        begin
          cbspeedhack.Checked := True;
          if cbspeedhack.Checked then
          begin
            editsh2.Text := format('%.3f', [speedhackspeed4.speed]);
            btnSetSpeedhack2.Click;

            if speedhackspeed4.disablewhenreleased then
            begin
              //spawn a timer
              if speedhackDisableTimer=nil then
              begin
                speedhackDisableTimer:=TTimer.create(self);
                speedhackDisableTimer.OnTimer:=@CheckForSpeedhackKey;
              end;

              speedhackDisableTimer.Interval:=hotkeyPollInterval;
              speedhackDisableTimer.Tag:=4;
              speedhackDisableTimer.enabled:=true;
            end;
          end;
        end;
      end;

      8:
      begin
        if cbspeedhack.Enabled then
        begin
          cbspeedhack.Checked := True;
          if cbspeedhack.Checked then
          begin
            editsh2.Text := format('%.3f', [speedhackspeed5.speed]);
            btnSetSpeedhack2.Click;

            if speedhackspeed5.disablewhenreleased then
            begin
              //spawn a timer
              if speedhackDisableTimer=nil then
              begin
                speedhackDisableTimer:=TTimer.create(self);
                speedhackDisableTimer.OnTimer:=@CheckForSpeedhackKey;
              end;

              speedhackDisableTimer.Interval:=hotkeyPollInterval;
              speedhackDisableTimer.Tag:=5;
              speedhackDisableTimer.enabled:=true;
            end;
          end;
        end;
      end;

      9:
      begin
        //increase speed
        try
          if cbspeedhack.Enabled then
          begin
            cbspeedhack.Checked := True;
            if cbspeedhack.Checked then
            begin
              a := strtofloat(editsh2.Text);
              a := a + speedupdelta;
              editsh2.Text := format('%.3f', [a]);
              btnSetSpeedhack2.Click;
            end;
          end;
        except

        end;
      end;


      10:
      begin
        //decrease speed
        try
          if cbspeedhack.Enabled then
          begin
            cbspeedhack.Checked := True;
            if cbspeedhack.Checked then
            begin
              b := strtofloat(editsh2.Text);
              b := b - slowdowndelta;
              editsh2.Text := format('%.3f', [b]);
              btnSetSpeedhack2.Click;
            end;
          end;
        except

        end;
      end;

      11..19: //Change type (if possible)
      begin
        if vartype.Enabled then
          vartype.ItemIndex := command-11
        else
        begin
          errorbeep;
        end;
      end;

      20://new scan
      begin

        if not btnNewScan.Enabled then
          exit; //only when no process is opened

        i := vartype.ItemIndex;

        if btnNewScan.Caption = strNewScan then
          btnNewScan.Click; //start new scan

        vartype.ItemIndex := i;
        vartype.OnChange(vartype); //set previous type
      end;

      21: //new scan Exact value
      begin

        if not btnNewScan.Enabled then
          exit;

        i := vartype.ItemIndex;
        s := scanvalue.Text;
        if s = '' then
          exit;

        if btnNewScan.Caption = strNewScan then
          btnNewScan.Click; //start new scan

        vartype.ItemIndex := i;
        vartype.OnChange(vartype); //set previous type

        scanvalue.Text := s;
        btnNewScan.Click;
      end;

      22: //new scan unknown initial value
      begin

        if not btnNewScan.Enabled then
          exit;

        i := vartype.ItemIndex;

        if btnNewScan.Caption = strNewScan then
          btnNewScan.Click; //start new scan

        vartype.ItemIndex := i;
        vartype.OnChange(vartype);

        scantype.ItemIndex := scantype.Items.IndexOf(StrUnknownInitialValue);
        scantype.OnChange(scantype);

        btnNewScan.Click;
      end;

      23: //next scan Exact value
      begin

        if not btnNewScan.Enabled then
          exit;


        if btnNextScan.Enabled then
        begin
          scantype.ItemIndex := scantype.Items.IndexOf(StrExactValue);
          scantype.OnChange(scantype);

          btnNextScan.click;
        end
        else
          Errorbeep;
      end;

      24: //next scan IncreasedValue
      begin

        if not btnNewScan.Enabled then
          exit;


        if btnNextScan.Enabled then
        begin
          scantype.ItemIndex := scantype.Items.IndexOf(StrIncreasedValue);
          scantype.OnChange(scantype);

          btnNextScan.click;
        end
        else
          Errorbeep;
      end;

      25: //next scan DecreasedValue
      begin

        if not btnNewScan.Enabled then
          exit;


        if btnNextScan.Enabled then
        begin
          scantype.ItemIndex := scantype.Items.IndexOf(StrDecreasedValue);
          scantype.OnChange(scantype);

          btnNextScan.click;
        end
        else
          Errorbeep;
      end;

      26: //next scan ChangedValue
      begin

        if not btnNewScan.Enabled then
          exit;


        if btnNextScan.Enabled then
        begin
          i:=scantype.Items.IndexOf(StrChangedValue);
          if i<>-1 then
          begin
            scantype.ItemIndex := i;
            scantype.OnChange(scantype);

            btnNextScan.click;
          end;
        end
        else
          Errorbeep;
      end;

      27: //next scan unchangedValue
      begin

        if not btnNewScan.Enabled then
          exit;


        if btnNextScan.Enabled then
        begin
          i:=scantype.Items.IndexOf(StrUnchangedValue);
          if i<>-1 then
          begin
            scantype.ItemIndex := i;
            scantype.OnChange(scantype);

            btnNextScan.click;
          end;
        end
        else
          Errorbeep;
      end;

      28: //next scan same as first
      begin
        if cbCompareToSavedScan.enabled then
          cbCompareToSavedScan.checked:=not cbCompareToSavedScan.checked;
      end;

      29: //undo lastscan
      begin

        if not btnNewScan.Enabled then
          exit;


        if undoscan.Enabled then
          UndoScanClick(nil)
        else
          Errorbeep;
      end;

      30: //cancel current scan
      begin
        if cancelbutton <> nil then
          cancelbutton.Click;
      end;

      31: //debug->run
      begin

        if memorybrowser.miDebugRun.enabled then
          MemoryBrowser.miDebugRun.Click;

      end;

    end;

end;

procedure TMainForm.hotkey(var Message: TMessage);
//stays because the old hotkeyhandler is still used in some places
begin
  {$ifdef windows}

  if (formhotkey <> nil) and (formhotkey.Visible) then
    exit;

  if Message.wparam = 0 then
  begin
    //bring to front
    try
      unregisterhotkey(mainform.handle, 0);

      if advancedoptions.Pausebutton.Down then
      begin
        beep;
        sleep(100);
        beep;
        sleep(100);
        beep;
        sleep(100);
        exit;
      end;

      beep;

      if formsettings.frameHotkeyConfig.cbHideAllWindows.Checked then
      begin
        ToggleWindow;

        //      ToggleOtherWindows;

        if formsettings.frameHotkeyConfig.cbCenterOnPopup.Checked then
          if not allwindowsareback then
            setwindowpos(mainform.Handle, HWND_NOTOPMOST, (screen.Width div 2) -
              (mainform.Width div 2), (screen.Height div 2) - (mainform.Height div
              2), mainform.Width, mainform.Height, SWP_NOZORDER or SWP_NOACTIVATE);

        if not allwindowsareback then
          application.BringToFront
        else
        begin
          setforegroundwindow(lastforeground);
          //   setactivewindow(lastactive);
        end;

        adjustbringtofronttext;
        exit;
      end;


      // if length(windowlist)<>0 then
      application.BringToFront;

      if formsettings.frameHotkeyConfig.cbCenterOnPopup.Checked then
        setwindowpos(mainform.Handle, HWND_NOTOPMOST, (screen.Width div 2) -
          (mainform.Width div 2), (screen.Height div 2) - (mainform.Height div
          2), mainform.Width, mainform.Height, SWP_NOZORDER or SWP_NOACTIVATE);

      formstyle := fsStayOnTop;

    finally
      registerhotkey(mainform.handle, 0, message.lparamlo, message.LParamHi);
      //restore the hotkey
    end;
  end;


  if message.WParam = 2 then //toggle speedhack
  begin

    try
      unregisterhotkey(mainform.handle, 2);
      if cbSpeedhack.Enabled then
      begin
        beep;
        cbSpeedhack.Checked := not cbSpeedhack.Checked;
      end;
    finally
      registerhotkey(mainform.handle, 2, message.lparamlo, message.LParamHi);
      //restore the hotkey
    end;

  end;
  {$endif}
end;


procedure TMainForm.PluginSync(var m: TMessage);
var
  func: TPluginFunc;
  params: pointer;
begin
  func := TPluginFunc(pointer(m.wparam));
  params := pointer(m.lparam);


  m.Result := ptruint(func(params));
end;

procedure TMainForm.ShowError;
var fn: string;
  nosaveerror: boolean;
  s: string;
  path: string;
begin

  try
    nosaveerror:=false;
    fn:=ExtractFileName(SaveDialog1.filename);
    if fn='' then
    begin
      fn:='noname.ct';
      path:=opendialog1.InitialDir;
    end
    else
    begin
      if lowercase(ExtractFileExt(fn))<>'.ct' then
        fn:=fn+'.ct';

      path:=ExtractFilePath(SaveDialog1.filename);
    end;



    fn:='ExceptionAutoSave_'+fn;
    fn:=path+fn;
    SaveTable(fn);
    nosaveerror:=true;
  except
  end;

  if nosaveerror then
  begin
    s:=currentexceptionerror+#13#10+'The current table has been saved to '+fn;
    MessageDlg(s, mterror,[mbok],0);
  end
  else
  begin
    MessageDlg(currentexceptionerror, mterror,[mbok],0);
  end;

end;

//----------------------------------

function TMainForm.getSelectedVariableType: TVariableType;
  {wrapper for the new getVarType2 in the new scanroutine}
begin
  Result := getVarType2;
end;

function TMainForm.getScanStart: ptruint;
begin
  try
    Result := symhandler.getAddressFromName(FromAddress.Text);
  except
    raise Exception.Create(Format(rsInvalidStartAddress, [FromAddress.Text]));
  end;
end;

procedure TMainForm.setScanStart(newscanstart: ptruint);
begin
  FromAddress.Text := inttohex(newscanstart, 8);
end;

function TMainForm.getScanStop: ptruint;
begin
  try
    Result := symhandler.getAddressFromName(ToAddress.Text);
  except
    raise Exception.Create(Format(rsInvalidStopAddress, [ToAddress.Text]));
  end;
end;

procedure TMainForm.setScanStop(newscanstop: ptruint);
begin
  ToAddress.Text := inttohex(newscanstop, 8);
end;


function TMainForm.getFastscan: boolean;
begin
  Result := cbFastscan.Enabled and cbFastscan.Checked;
end;

procedure TMainForm.setFastScan(state: boolean);
begin
  cbFastscan.Checked := state;
end;




function TMainForm.GetRoundingType: TRoundingType;
  {Property function to get the current rounding type}
begin
  Result := rtTruncated;
  if rt1.Checked then
    Result := rtRounded
  else
  if rt2.Checked then
    Result := rtExtremerounded
  else
  if rt3.Checked then
    Result := rtTruncated;
end;

procedure TMainForm.SetRoundingType(rt: TRoundingType);
{Property function to set the current rounding type}
begin
  case rt of
    rtRounded: rt1.Checked;
    rtExtremerounded: rt2.Checked;
    rtTruncated: rt3.Checked;
  end;
end;


procedure TMainForm.setfoundcount(x: int64);
var
  xdouble: double;
begin
  ffoundcount := x;
  xdouble := x;
  foundcountlabel.Caption := Format('%.0n', [xdouble]);
end;

procedure TMainForm.DestroyCancelButton;
begin
  if cancelbutton <> nil then
    FreeAndNil(cancelbutton);
  if cancelbuttonenabler <> nil then
    FreeAndNil(cancelbuttonenabler);
end;

procedure TMainForm.SpawnCancelButton;
begin
  cancelbutton := TButton.Create(self);
  with cancelbutton do
  begin
    Anchors := btnNewScan.Anchors;
    top := btnNewScan.top;
    left := btnNewScan.left;
    Width := (btnNextScan.left + btnNextScan.Width) - left;
    Height := btnNewScan.Height;
    Caption := rsCancel;
    onclick := @cancelbuttonclick;
    Enabled := False;
    tag := 0; //0=normal 1=force

    Hint := rsThisButtonWillTryToCancelTheCurrentScanClickTwiceT;
    ParentShowHint := False;
    ShowHint := True;


    cancelbutton.Anchors:=[];
    cancelbutton.AnchorSideLeft.Control:=btnNewScan;
    cancelbutton.AnchorSideLeft.Side:=asrLeft;
    cancelbutton.Anchors:=[akLeft, akTop];
    cancelbutton.name:='CancelButton';

    parent := panel5;
  end;

  cancelbuttonenabler := TTimer.Create(self);

  with cancelbuttonenabler do
  begin
    interval := 2000; //2 seconds
    OnTimer := @cancelbuttonenablerinterval;
    Enabled := True;
  end;
end;


procedure TMainForm.disableGui;
{
This procedure will disable the gui. E.g while scanning the memory with no wait
screen.
}
begin
  setGbScanOptionsEnabled(False);

  scanvalue.Enabled := False;
  if scanvalue2 <> nil then
  begin
    scanvalue2.Enabled := False;
    andlabel.Enabled := False;
    scantext2.Enabled := False;
  end;

  vartype.Enabled := False;
  scantype.Enabled := False;
  scantext.Enabled := False;
  lblScanType.Enabled := False;
  lblValueType.Enabled := False;
  cbHexadecimal.Enabled := False;
  cbCaseSensitive.Enabled := False;

  btnNewScan.Enabled := False;
  btnNextScan.Enabled := False;
  undoscan.Enabled := False;

  cbNot.Enabled:=false;
  cbLuaFormula.enabled:=false;
  cbNewLuaState.enabled:=false;
end;

procedure TMainForm.enableGui(isnextscan: boolean);
{
Enables the gui options according to what type of scan is currently used
no scan, enable everything
already scanning, disable the group and type
}
var
  scanstarted: boolean;
begin

  scanstarted := btnNewScan.Caption = strnewscan;

  if not scanstarted then
  begin
    setGbScanOptionsEnabled(True);
  end;

  scanvalue.Enabled := True;
  if scanvalue2 <> nil then
  begin
    scanvalue2.Enabled := True;
    andlabel.Enabled := True;
    scantext2.Enabled := True;
  end;
  btnNewScan.Enabled := True;

  undoscan.Enabled := isnextscan and memscan.canUndo; //nextscan was already enabled
  btnNextScan.Enabled := scanstarted;
  vartype.Enabled := not scanstarted;
  scantype.Enabled := True;
  scantext.Enabled := True;
  lblScanType.Enabled := True;
  lblValueType.Enabled := True;
  cbHexadecimal.Enabled := True;
  cbCaseSensitive.Enabled := True;
  cbNot.enabled:=true;
  cbLuaFormula.enabled:=true;
  cbNewLuaState.enabled:=true;


  scanvalue.Visible := True;
  scantext.Visible := True;

  Updatescantype;
  Scantype.ItemIndex := 0;

  //-----------------------
  //Get the expectedFilename
  //-----------------------
  SetExpectedTableName;

  cbspeedhack.Enabled := True;
  cbunrandomizer.Enabled := True;

end;



procedure TMainForm.toggleWindow;
var
  c: integer;
begin
  togglewindows := TTogglewindows.Create(False);
  c := 0;
  while togglewindows <> nil do
  begin
    if c = 500 then
    begin
      freeandnil(togglewindows);
      raise Exception.Create(strWindowFailedToHide);
    end;
    sleep(10);
    Inc(c);
  end;
end;

procedure TMainForm.exceptionhandler(Sender: TObject; E: Exception);
var
  s: string;
  op: string;
begin
  //unhandled exeption. Also clean lua stack
  s:={$ifdef THREADNAMESUPPORT}GetThreadName+': '+{$endif}'Unhandled exception: '+e.message+' (Exception class '+ e.ClassName+')';


  {$ifdef windows}
  if e is EAccessViolation then
  begin
    case EAccessViolation(e).ExceptionRecord^.ExceptionInformation[0] of
      0: op:='read';
      1: op:='write to';
      8: op:='execute';
      else op:='do something weird with';
    end;

    s:=s+' (tried to '+op+' address '+inttohex(qword(EAccessViolation(e).ExceptionRecord^.ExceptionInformation[1]),8)+')';
  end;
  {$endif}


  if TraceExceptions then
  begin
    DebugLn(s);


    DumpExceptionBackTrace;

    s:=s+#13#10'Please send the cedebug.txt file to Dark Byte. Thanks';
  end;

  if showingException then exit; //don't bother showing another one. Just read the log

  if exceptionerrorcs.TryEnter then //it's not important if it's already showing another error
  begin
    if showingException=false then //should be the case, but check anyhow
    begin
      currentexceptionerror:=s;

      showingException:=true;
      if MainThreadID=GetCurrentThreadId then
        showerror
      else
        tthread.Synchronize(nil, @showerror);

      showingException:=false;
    end;

    exceptionerrorcs.leave;
  end;
end;



function TMainForm.CheckIfSaved: boolean;
var
  help: word;
begin
  //result:=true;
  Result := not editedsincelastsave;


  if itemshavechanged then
    Result := False;

  if Result = False then
  begin
    help := messagedlg(strAskToSave, mtConfirmation, mbYesNoCancel, 0);
    case help of
      mrCancel: Result := False;
      mrYes:
      begin

        SaveButton.click;
        result:=not savegotcanceled;
      end;
      else
        Result := True;
    end;
  end;
end;





//--------------------------cbpercentage--------------
procedure TMainForm.cbPercentageOnChange(Sender: TObject);
begin
  if cbpercentage.Checked then
  begin
    //turn this into a double value scan like "value between"
    CreateScanValue2;
    ScanText.Caption := rsValue;
    ScanText2.Caption := rsValue;
  end
  else
  begin
    if ScanType.Text <> strValueBetween then
    begin
      //single value scan
      ScanText.Caption := strScantextcaptiontoValue;
      DestroyScanValue2;
    end
    else
    begin
      ScanText.Caption := strScantextcaptiontoValue;
      ScanText2.Caption := strScantextcaptiontoValue;
    end;
  end;
end;

procedure TMainForm.CreateCbPercentage;
begin
  cbpercentage.visible:=true;

  if ScanType.Text = strValueBetween then
    cbpercentage.Caption := rsBetween
  else
    cbpercentage.Caption := rsAtLeastXx;

  UpdateFloatRelatedPositions;
end;

procedure TMainForm.DestroyCbPercentage;
begin
  cbpercentage.Visible:=false;
end;
//------------------

procedure TMainForm.CreateScanValue2;
begin
  scantext2.Caption := scantext.Caption;

  andlabel.Visible:=true;
  scanvalue2.visible:=true;
  scantext2.visible:=true;

  panel5.OnResize(panel5);
end;

procedure TMainForm.DestroyScanValue2;
begin
  scanvalue2.visible:=false;
  scantext2.visible:=false;
  andlabel.visible:=false;
end;

procedure TMainForm.UpdateScanType;
var
  OldText: string;
  OldIndex: integer;
  hexvis: boolean;
  floatvis: boolean;
  t: TStringList;
  old, old2: TNotifyEvent;
  ct: Tcustomtype;
begin
  old := scantype.OnChange;
  old2 := scantype.OnSelect;
  scantype.OnChange := nil;
  scantype.OnSelect := nil;
  ct:=TCustomtype(vartype.Items.Objects[vartype.itemindex]);

  try
    OldIndex := Scantype.ItemIndex;
    OldText := Scantype.Text;
    hexvis := True;
    floatvis := False;

    ScanType.Items.Clear;

    ScanText.Caption := strScantextcaptiontoValue;



    if (varType.ItemIndex in [VARTYPE_INDEX_BYTE, VARTYPE_INDEX_WORD, VARTYPE_INDEX_DWORD, VARTYPE_INDEX_QWORD,
                              VARTYPE_INDEX_SINGLE, VARTYPE_INDEX_DOUBLE, VARTYPE_INDEX_ALL,VARTYPE_INDEX_GROUPED]) or
       (vartype.ItemIndex >= VARTYPE_INDEX_CUSTOMBASE) then
      //byte-word-dword--8bytes-float-double-all   - custom
    begin
      if (ct<>nil) and ct.scriptUsesString then
      begin
        //same as stringscan
        ScanText.Caption := strScanTextCaptionToText;
        ScanType.Items.Add(strSearchForText);
        hexvis := False;
      end
      else
      begin

        if (vartype.ItemIndex in [VARTYPE_INDEX_SINGLE, VARTYPE_INDEX_DOUBLE, VARTYPE_INDEX_ALL, VARTYPE_INDEX_GROUPED]) or (vartype.ItemIndex >= VARTYPE_INDEX_CUSTOMBASE) then //float/all/grouped, custom
        begin

          if (ct=nil) or (ct.scriptUsesFloat) then
          begin
            //handle as a float value
            if oldindex = 0 then
              floatvis := True;

            if vartype.ItemIndex <> VARTYPE_INDEX_ALL then
              hexvis := False;
          end;
        end;

        ScanType.Items.Add(strExactValue);
        ScanType.Items.Add(strBiggerThan);
        ScanType.Items.Add(strsmallerThan);
        ScanType.Items.Add(strValueBetween);

        if btnNextScan.Enabled then
        begin
          scantype.Items.Add(strIncreasedValue);
          Scantype.Items.Add(strIncreasedValueBy);
          ScanType.Items.Add(strDecreasedValue);
          ScanType.Items.Add(strDecreasedValueBy);
          ScanType.Items.add(strChangedValue);
          ScanType.Items.Add(strUnchangedValue);
          ScanType.Items.Add(strIgnoreValue);


          cbCompareToSavedScan.visible:=true;
          t:=tstringlist.create;
          if memscan.getsavedresults(t)>1 then
            cbCompareToSavedScan.caption:=rsCompareToSavedScan
          else
            cbCompareToSavedScan.caption:=strCompareToFirstScan;

          t.free;
        end
        else
        begin
          ScanType.Items.Add(strUnknownInitialValue);

        end;
      end;
    end
    else

      case varType.ItemIndex of
        VARTYPE_INDEX_BINARY:
        begin
          ScanType.Items.Add(strExact);

        end;



        VARTYPE_INDEX_TEXT:
        begin  //text
          ScanText.Caption := strScanTextCaptionToText;
          ScanType.Items.Add(strSearchForText);
          //perhaps also a changed value and unchanged value scan

          hexvis := False;
        end;

        VARTYPE_INDEX_AOB:
        begin  //array of bytes
          ScanText.Caption := vartype.Items[8];
          ScanType.Items.Add(strSearchforarray);

        end;

      end;
    Scantype.DropDownCount := Scantype.items.Count;



    if (oldtext = strUnknownInitialValue) and (btnNextScan.Enabled) then
      scantype.ItemIndex := 0
    else
      scantype.ItemIndex := oldindex;

    if (scantype.Text = strIncreasedValueBy) or (scantype.Text = strDecreasedValueBy) or
      (scantype.Text = strValueBetween) then
    begin
      if btnNextScan.Enabled then
        createCbPercentage;

    end
    else
    begin
      destroyCbPercentage;

    end;

    if scantype.Text = strValueBetween then
      CreateScanValue2
    else
      DestroyScanValue2;


    if (scantype.Text = strIncreasedValue) or (scantype.Text = strDecreasedValue) or
      (scantype.Text = strChangedValue) or (scantype.Text = strUnchangedValue) or
      (scantype.Text = strUnknownInitialValue) or (scantype.Text = strIgnoreValue) then
    begin
      Scantext.Visible := False;
      Scanvalue.Visible := False;
      cbHexadecimal.Visible := False;
      cbNot.visible:=false;
    end
    else
    begin
      Scantext.Visible := True;
      Scanvalue.Visible := True;
      cbHexadecimal.Visible := hexvis;

      cbNot.Visible:=not ((vartype.itemindex in [VARTYPE_INDEX_BINARY,VARTYPE_INDEX_TEXT,VARTYPE_INDEX_AOB,VARTYPE_INDEX_GROUPED]) or ((ct<>nil) and ct.scriptUsesString ));
    end;

    pnlfloat.Visible := floatvis;

    if rbBit.Visible then
      cbHexadecimal.Visible := False;

    pnlScanValueOptions.visible:=(cbHexadecimal.Visible or rbDec.visible or rbBit.Visible);


    //save the last scantype (if it wasn't the option to change between first/last)
    if (scantype.ItemIndex <> -1) and (scantype.ItemIndex < scantype.Items.Count) then
    begin
      if not ((scantype.items[scantype.ItemIndex] = strcompareToSavedScan) or
        (scantype.items[scantype.ItemIndex] = strCompareToLastScan)) then
        lastscantype := scantype.ItemIndex;
    end;

    if (not cbHexadecimal.Visible) and (cbHexadecimal.checked) then //not visible but checked
    begin
      cbHexadecimal.checked:=hexvis;
    end;

    UpdateFloatRelatedPositions;


    cbRepeatUntilStopped.visible:=GetScanType=soUnchanged;

    cbLuaFormula.visible:=(GetScanType=soExactValue) and (getVarType in [vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble, vtCustom, vtAll]) and ((ct=nil) or (ct.scriptUsesString=false));
    cbNewLuaState.visible:=cbLuaFormula.checked;
  finally
    scantype.OnChange := old;
    scantype.OnSelect := old2;
  end;
end;


procedure TMainForm.reinterpretaddresses;
begin
  if addresslist <> nil then
    addresslist.ReinterpretAddresses;
end;



procedure TMainForm.AddAutoAssembleScript(script: string);
begin
  addresslist.addAutoAssembleScript(script);
end;

procedure TMainForm.AddToRecord(Line: integer; node: TTreenode = nil;
  attachmode: TNodeAttachMode = naAdd);
var
  Address: ptrUint;
  startbit: integer;
  i,l: integer;

  vt: TVariableType;
  tempvartype: TVariableType;
  addressstring: string;
  newaddresstring: string;

  ct: TCustomType;
  customname: string;
  m: TMemoryRecord;
  ga: PGroupAddress;

  gcp: TGroupscanCommandParser;

  extra: dword;
  value: string;
begin

  //first check if this address is already in the list!
  customname := '';
  l := 0;
  startbit := 0;
  extra:=0;
  ct:=nil;
  gcp:=nil;
  ga:=nil;

  vt := getvartype;
  if vt = vtBinary then //binary
  begin
    startbit := foundlist.getstartbit(line);
    l := memscan.Getbinarysize;
  end
  else
  if vt = vtAll then //all
  begin
    address:=foundlist.GetAddress(line, extra, Value);

    if extra >= $1000 then
    begin
      ct:=TCustomType(customTypes[extra - $1000]);
      customname := ct.Name;
      vt:=vtCustom;
    end
    else
    begin
      ct:=nil;
      vt := TVariableType(foundlist.getstartbit(line));
    end;


  end
  else
  if vt=vtCustom then //custom
  begin
    ct := TCustomType(vartype.items.objects[vartype.ItemIndex]);
    customname := ct.Name;
  end
  else
  begin
    startbit := 0;
    l := foundlist.GetVarLength;
  end;
  address := foundlist.GetAddress(line);

  if foundlist.inmodule(line) then
    addressString := foundlist.GetModuleNamePlusOffset(line)
  else
    addressstring := inttohex(address, 8);


  if vt=vtGrouped then
  begin
    //add as a group
    ga:=foundlist.GetGroupAddress(line);
    if ga=nil then
      raise exception.create(rsGroupscanDataInvalid);

    gcp:=foundlist.getGCP;
    if gcp=nil then
      raise exception.create(rsGroupscanResultWithNoGroupscanparser);


    for i:=0 to length(gcp.elements)-1 do
    begin
      if gcp.elements[i].picked then
      begin
        if gcp.elements[i].customtype<>nil then
          customname:=gcp.elements[i].customtype.name
        else
          customname:='';

        l:=gcp.elements[i].bytesize;

        vt:=gcp.elements[i].vartype;
        if vt=vtUnicodeString then
        begin
          vt:=vtString;
          l:=l div 2;
        end;

        newaddresstring:=addressstring+'+'+inttohex(ga^.offsets[i],1);
        addresslist.addaddress(strNoDescription, newaddresstring, [], 0, vt, customname, l, 0, gcp.elements[i].vartype=vtUnicodeString, node, attachmode);
      end;
    end;

  end
  else
  begin
    m := addresslist.addaddress(strNoDescription, addressString, [], 0,
      vt, customname, l, startbit, False, node, attachmode);

    m.showAsHex:=foundlist.isHexadecimal;

    if m.VarType = vtBinary then
      m.Extra.bitData.showasbinary := rbBit.Checked
    else
    if (m.VarType = vtString) then
    begin
      m.Extra.stringData.unicode := foundlist.isUnicode;
      m.Extra.stringData.codepage := memscan.codePage;
    end;
  end;

end;

procedure TMainForm.SetExpectedTableName;
var
  fname: string;
  expectedfilename: string;
begin
  if UserDefinedTableName<>'' then exit;


  Fname := copy(processlabel.Caption, pos('-', processlabel.Caption) + 1,
    length(processLabel.Caption));


  if (length(fname)>3) and (FName[length(FName) - 3] = '.') then  //it's a filename
    expectedFilename := copy(FName, 1, length(FName) - 4)
  else //it's a normal title;
    expectedFilename := FName;

  savedialog1.FileName := expectedFilename;
  Opendialog1.FileName := expectedFilename;
end;



function TMainForm.openprocessPrologue: boolean;
begin
  if (processid<>0) and Globals.SyncSymbols then
    SyncSymbolsNow;

  Result := False;

  if flashprocessbutton <> nil then
  begin
    flashprocessbutton.Terminate;
    FreeAndNil(flashprocessbutton);
  end;


  canceled := False;
  Result := True;
end;

procedure TMainForm.openProcessEpilogue(oldprocessname: string; oldprocess: dword; oldprocesshandle: dword; autoattachopen: boolean);
var
  i, j: integer;
  fname, expectedfilename: string;
  path: string;

  wasActive: boolean;
  DoNotOpenAssociatedTable: boolean;
  //set to true if the table had AA scripts enabled or the code list had nopped instruction
begin
  if MainThreadID <> GetCurrentThreadId then
  begin
    currentexceptionerror:='openProcessEpilogue wasn''t called from the main GUI thread. Do not do this!';
    tthread.Synchronize(nil, @ShowError);
    exit;
  end;

  if getConnection<>nil then
    updateNetworkOptions;

  {$ifdef windows}
  if aprilfools then decreaseCheatECoinCount;
  {$endif}

  DoNotOpenAssociatedTable:=false;

  outputdebugstring('openProcessEpilogue called');

  if (oldprocess<>processid) and SyncSymbols and symsync_ClearSymbolListWhenOpeningADifferentProcess then
    symhandler.DeleteAllUserdefinedSymbols;

  if SyncSymbols then
    SyncSymbolsNow(true); //get the latest symbols

  symhandler.reinitialize(true);
//  symhandler.waitforsymbolsloaded;

  reinterpretaddresses;

  miNetwork.visible:=processhandler.isNetwork;

  if oldprocess = 0 then //set disassembler and hexview of membrowser to what the main header says
    memorybrowser.setcodeanddatabase;

  outputdebugstring('After setcodeanddatabase');

  if processid = $FFFFFFFF then
  begin
    if ProcessHandler.ProcessHandle<>QWORD(-2) then
      processlabel.Caption := strPhysicalMemory;

    cbPauseWhileScanning.visible:=false;

    if cbsaferPhysicalMemory=nil then
    begin
      cbsaferPhysicalMemory:=tcheckbox.create(self);
      cbsaferPhysicalMemory.Caption:=strSaferPhysicalMemory;
      cbsaferPhysicalMemory.Checked:={$ifdef windows}dbk32functions.saferQueryPhysicalMemory{$else}false{$endif};
      cbsaferPhysicalMemory.AnchorSame(akTop,cbPauseWhileScanning);                    // trick with AnchorSame
      cbsaferPhysicalMemory.AnchorSame(akLeft,cbPauseWhileScanning);
      cbsaferPhysicalMemory.AnchorSame(akRight,cbPauseWhileScanning);
      cbsaferPhysicalMemory.AnchorSame(akBottom,cbPauseWhileScanning);
      cbsaferPhysicalMemory.BorderSpacing.Assign(cbPauseWhileScanning.BorderSpacing);  // clone spacing
      cbsaferPhysicalMemory.OnChange:=@cbSaferPhysicalMemoryChange;
      cbsaferPhysicalMemory.Parent:=cbPauseWhileScanning.Parent;
      cbsaferPhysicalMemory.Name:='cbsaferPhysicalMemory';
    end;
  end
  else
  begin
    //restore cbPauseWhileScanning if it was replaced
    if cbSaferPhysicalMemory<>nil then
    begin
      freeandnil(cbsaferPhysicalMemory);
      cbPauseWhileScanning.Visible:=true;
    end;
  end;



  if (processhandle = 0) then
  begin
    outputdebugstring('processhandle is 0, so disabling gui');

    if btnNewScan.Caption = strNewScan then
      btnNewScan.click;

    //disable everything

    foundcount := 0;
    if foundlist<>nil then
      foundlist.Clear;

    btnNewScan.Caption := strFirstScan;

    setGbScanOptionsEnabled(False);


    scanvalue.Enabled := False;
    btnNewScan.Enabled := False;
    btnNextScan.Enabled := False;
    vartype.Enabled := False;
    scantype.Enabled := False;
    scantext.Enabled := False;
    lblScanType.Enabled := False;
    lblValueType.Enabled := False;

    scanvalue.Visible := False;
    scantext.Visible := False;
    scanvalue.Text := '';
    cbHexadecimal.Enabled := False;
    cbCaseSensitive.Enabled := False;
    cbNot.Visible:=false;

    Updatescantype;
    Scantype.ItemIndex := 0;

    cbSpeedhack.Enabled := False;
    cbUnrandomizer.Enabled := False;

    if processid <> $FFFFFFFF then
    begin
      processlabel.Caption := strError;
      MessageDlg(strErrorWhileOpeningProcess{$ifdef darwin}+strErrorwhileOpeningProcessMac{$endif}, mtError,[mbok],0);
      exit;
    end
    else
    begin
      if processhandle<>qword(-2) then
        processlabel.Caption := strPhysicalMemory;
    end;

    UpdateScanType;


    //apply this for all tabs
    if scantablist <> nil then
      for i := 0 to scantablist.Count - 1 do
        SaveCurrentState(PScanState(scantablist.TabData[i]), true);

  end;

  if (processID = oldProcess) then
    exit;

  outputdebugstring('oldprocessid != processid');

  //a new process has been selected
  cbspeedhack.Enabled := True;
  cbunrandomizer.Enabled := True;

  if not autoattachopen then
  begin
    if (addresslist.Count > 0) or (AdvancedOptions.count > 0) then
    begin
      if formsettings.cbAskToClearListOnOpen.checked and (messagedlg(strKeepList, mtConfirmation, [mbYes, mbNo], 0) = mrNo) then
      begin
        UserDefinedTableName:='';
        ClearList;
      end
      else
      begin
        //yes, so keep the list
        //go through the list and chek for auto assemble entries, and check if one is enabled. If so, ask to disable (withotu actually disabling)
        wasActive := False;
        DoNotOpenAssociatedTable:=true; //user kept the list, do not load the associated table

        for i := 0 to addresslist.Count - 1 do
          if (addresslist[i].VarType = vtAutoAssembler) and (addresslist[i].active) then
          begin
            wasActive := True;
            break;
          end;

        if not wasActive then
        begin
          for i := 0 to AdvancedOptions.count - 1 do
            if (AdvancedOptions.code[i]<>nil) and AdvancedOptions.code[i].changed then
            begin
              wasActive := True;
              break;
            end;
        end;

        if wasactive then
        begin
          if (messagedlg(rsThereAreOneOrMoreAutoAssemblerEntriesOrCodeChanges,
            mtConfirmation, [mbYes, mbNo], 0) = mrYes) then
          begin
            addresslist.disableAllWithoutExecute;

            for i := 0 to AdvancedOptions.count - 1 do
              if (AdvancedOptions.code[i]<>nil) then AdvancedOptions.code[i].changed := False;
          end;

        end;
      end;

    end;
  end
  else
  begin
    if (oldprocess<>0) and (processid<>oldprocess) then
    begin
      cbSpeedhack.Checked:=false;
      addresslist.disableAllWithoutExecute;
      for i := 0 to AdvancedOptions.count - 1 do
        if AdvancedOptions.code[i]<>nil then AdvancedOptions.code[i].changed := False;
    end;
  end;

  enablegui(btnNextScan.Enabled);

  Fname := copy(processlabel.Caption, pos('-', processlabel.Caption) +
    1, length(processLabel.Caption));

  if (length(fname)>3) and (FName[length(FName) - 3] = '.') then  //it's a filename
    expectedFilename := copy(FName, 1, length(FName) - 4) + '.ct'
  else //it's a normal title;
    expectedFilename := FName + '.ct';



  if not (autoattachopen or DoNotOpenAssociatedTable) then
  begin
    path:='';

    if fileexists(TablesDir +  pathdelim + expectedfilename) then
      path:=TablesDir +  pathdelim + expectedfilename
    else
    if fileexists(expectedfilename) then
      path:=expectedfilename
    else if fileexists(cheatenginedir + expectedfilename) then
      path:=cheatenginedir + expectedfilename
    else if fileexists( IncludeTrailingPathDelimiter(opendialog1.InitialDir)+expectedfilename) then
      path:=IncludeTrailingPathDelimiter(opendialog1.InitialDir)+expectedfilename
    else if fileexists( IncludeTrailingPathDelimiter(extractfilepath(opendialog1.FileName))+expectedfilename) then
      path:=IncludeTrailingPathDelimiter(extractfilepath(opendialog1.FileName))+expectedfilename;

    if path<>'' then
    begin
      if messagedlg(Format(rsLoadTheAssociatedTable, [expectedFilename]),
        mtConfirmation, [mbYes, mbNo], 0) = mrYes then
      begin
        autoopen := True;
        if fileexists(path) then
          opendialog1.FileName := path;

        LoadButton.Click;
      end;
    end;
  end;
  UpdateScanType;

  if scantablist <> nil then
    for i := 0 to scantablist.Count - 1 do
      SaveCurrentState(PScanState(scantablist.TabData[i]),true);


  {$ifdef darwin}
  if formsettings.cbUseRosettaDebugserver.checked and formsettings.cbAttachDebuggerToRosettaOnProcessOpen.checked and isProcessTranslated(processid) then
  begin
    if (formsettings.cbaskToAttachToRosetta.Checked=false) or (MessageDlg('The selected process is running under Rosetta. To be able to edit programcode the debugger needs to be attached. Attach the debugger now?', mtConfirmation, [mbyes,mbno],0)=mryes) then
      startdebuggerifneeded(false);
  end;
  {$endif}


  outputdebugstring('openProcessEpilogue exit');

 // miDotNET.visible:=symhandler.hasDotNetAccess; //too slow to use. You're free to uncomment it but don't bitch about having to wait 2 and a half hour

  if assigned(fOnProcessOpened) then
    fOnProcessOpened(processid, processhandle, processlabel.Caption);
end;

procedure TMainForm.ShowProcessListButtonClick(Sender: TObject);
var
  oldprocess: Dword;
  resu: integer;
  oldprocesshandle: thandle;
  oldprocessname: string;
begin
  if not openprocessPrologue then
    exit;

  oldprocessname := copy(mainform.ProcessLabel.Caption, pos(
    '-', mainform.ProcessLabel.Caption) + 1, length(mainform.ProcessLabel.Caption));

  oldprocess := processID;
  oldprocesshandle := processhandle;

  if Processwindow = nil then
    ProcessWindow := TProcessWindow.Create(application);

  resu := ProcessWindow.ShowModal;

  if resu = mrCancel then
    exit;

  openProcessEpilogue(oldprocessname, oldprocess, oldprocesshandle);
end;


procedure TMainForm.rbFsmAlignedChange(Sender: TObject);
begin
  if rbfsmLastDigts.Checked then
    alignsizechangedbyuser := False;

  VarType.OnChange(vartype);
end;

procedure TMainForm.rtChange(Sender: TObject);
begin
  cereg.writeInteger('Last Rounding Type',TComponent(sender).tag);
end;


procedure TMainForm.Save1Click(Sender: TObject);
var
  protect: boolean;
begin
  protect := False;
  if (savedialog1.FileName = '') then
    actSave.Execute
  else
    savetable(savedialog1.FileName);
end;



procedure TMainForm.Description1Click(Sender: TObject);
begin
  addresslist.doDescriptionChange;
end;

procedure TMainForm.edtAlignmentKeyPress(Sender: TObject; var Key: char);
begin
  if rbFsmAligned.Checked then
    alignsizechangedbyuser := True;
end;

procedure TMainForm.FormDropFiles(Sender: TObject; const FileNames: array of string);
var
  merge: boolean;
  app: word;
  ext: string;
begin
  merge:=false;
  if length(filenames) > 0 then
  begin
    ext:=ExtractFileExt(filenames[0]);
    if lowercase(ext)<>'.ct' then exit;

    if not (fsVisible in formstate) then exit;


    if CheckIfSaved then
    begin
      if ((addresslist.Count > 0) or (advancedoptions.count > 0) or (DissectedStructs.count>0) )then
      begin
        app := messagedlg(rsDoYouWishToMergeTheCurrentTableWithThisTable, mtConfirmation, mbYesNoCancel, 0);
        case app of
          mrCancel: exit;
          mrYes: merge := True;
          mrNo: merge := False;
        end;
      end;

      LoadTable(filenames[0], merge);
      reinterpretaddresses;

      if not merge then
      begin
        Savedialog1.FileName := filenames[0];
        Opendialog1.FileName := filenames[0];
      end;
    end;
  end;
end;

procedure TMainForm.Foundlist3ColumnClick(Sender: TObject; Column: TListColumn);
begin
  if column.index>=1 then
    setActivePreviousResultColumn(column.index);
end;

procedure TMainForm.Foundlist3CustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: boolean);
var
  s: string;
begin
  if foundlist <> nil then
  begin
    if foundlist.inmodule(item.index) then
      foundlist3.Canvas.Font.Color := foundlistColors.StaticColor
    else
      foundlist3.Canvas.Font.Color := foundlistColors.DynamicColor;
  end;
end;

procedure TMainForm.Foundlist3CustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var r: trect;
  ts: TTextStyle;
  drawn:boolean;

  fc: TColor;

  _changed: boolean;

  subitemCompareIndex: integer;

  sic: integer;
begin
  //apparently the SubItem field includes the main item as well at index 0   (lazarus bug? Will be fixed someday? If so, expect crashes here)
  if subitem=0 then exit;
  subitem:=subitem-1;

  drawn:=false;
  if miShowPreviousValue.checked and (PreviousResultList.count>0) then
  begin
    sic:=item.SubItems.count;
    subitemCompareIndex:=ActivePreviousResultColumn-1;

    if (subitemCompareIndex>=sic) or (subitem>=sic) or (sic=0) then
      exit;

    if subitem=0 then //current value
    begin
      //compare it against the currently selected compareto selection
      _changed:=(item.subItems[subitemCompareIndex]<>rsPleaseWait) and (item.subitems[0]<>item.subitems[subitemCompareIndex]);
    end
    else
    begin
      //compare against the current value
      _changed:=(item.subItems[subitem]<>rsPleaseWait) and (item.subitems[0]<>item.subitems[subitem]);
    end;

    if _changed then
    begin
      sender.Canvas.Font.color:=foundlistColors.changedValueColor;
      sender.canvas.font.Style:=sender.canvas.font.Style+[fsBold];
      sender.canvas.Refresh;

      drawn:=true;

      {$ifdef darwin}
      //no color or customdrawn support
      //item.subitems[0]:='* '+item.subitems[0]+' *';
      {$endif}
    end;
  end;
  if(not drawn)then
  begin
    sender.Canvas.Font.color:=foundlistColors.NormalValueColor;
  end;
end;

procedure TMainForm.Address1Click(Sender: TObject);
begin
  addresslist.doAddressChange;
end;

procedure TMainForm.cbCompareToSavedScanChange(Sender: TObject);
var
  s: tstringlist;
  l: TfrmSelectionList;
  i,selindex: integer;

  str: string;
begin
  if cbCompareToSavedScan.checked then
  begin
    s := TStringList.Create;
    try
      selindex:=-1;
      if (memscan.getsavedresults(s) > 1) then
      begin
        //popup a window where the user can select the scanresults
        //currentlySelectedSavedResultname
        l := TfrmSelectionList.Create(self, s);
        l.Caption := rsSavedScanResults;
        l.label1.Caption := rsSelectTheSavedScanResultFromTheListBelow;
        l.ItemIndex := 0;

        selindex:=l.ItemIndex;

        if (l.showmodal = mrOk) and (l.ItemIndex <> -1) then
          currentlySelectedSavedResultname := l.selected
        else
          exit;
      end
      else
        currentlySelectedSavedResultname := rsFirst;

      //compareToSavedScan := True;
      //lblcompareToSavedScan.Visible := s.Count>1;
      //lblcompareToSavedScan.Caption := '('+currentlySelectedSavedResultname+')';
    finally
      freeandnil(s);
    end;

    for i:=0 to PreviousResultList.count-1 do
    begin
      str:=uppercase(TSavedScanHandler(PreviousResultList[i]).name);
      if str=uppercase(currentlySelectedSavedResultname) then
      begin
        ActivePreviousResultColumn:=i+2;
        foundlist3.Refresh;
        exit;
      end;
    end;

    //language issues...
    if selindex<>-1 then
      ActivePreviousResultColumn:=2+selindex;
  end
  else
  begin
    //unchecked, so compare against the last scan results
    compareToSavedScan := False;
    lblcompareToSavedScan.Visible := False;

    ActivePreviousResultColumn:=2; //the TMP one
    foundlist3.Refresh;
  end;
end;

procedure TMainForm.cbLuaFormulaChange(Sender: TObject);
begin
  cbNewLuaState.visible:=cbLuaFormula.Visible and cbLuaFormula.Checked;
end;

procedure TMainForm.cbCodePageChange(Sender: TObject);
begin
  if cbCodePage.checked then cbunicode.Checked:=false;
end;

procedure TMainForm.cbRepeatUntilStoppedChange(Sender: TObject);
begin
  if (cbRepeatUntilStopped.checked=false) and (repeatscantimer<>nil) then
    freeandnil(repeatscantimer);
end;

procedure TMainForm.cbUnicodeChange(Sender: TObject);
begin
  if cbunicode.checked then cbCodePage.checked:=false;
end;

procedure TMainForm.Copyselectedaddresses1Click(Sender: TObject);
var
  i: ptruint;
  address: ptruint;
  temp: string;
begin
  temp:='';

  if foundlist3.SelCount = 1 then
    begin
      address := foundlist.GetAddress(foundlist3.itemIndex);
      clipboard.AsText := symhandler.getNameFromAddress(address)
    end
  else
  if foundlist3.SelCount > 1 then
  begin
    for i:=0 to foundlist3.Items.count-1 do
    begin
      if foundlist3.items[i].Selected then
      begin
        address := foundlist.GetAddress(i);
        temp := temp + symhandler.getNameFromAddress(address) + sLineBreak;
      end
    end;
    clipboard.AsText := temp;
  end;
end;

procedure TMainForm.EnableLCLClick(Sender: TObject);
var llf: TLazLoggerFile;
begin
  llf:=GetDebugLogger;
  if llf<>nil then
  begin
    llf.CloseLogFileBetweenWrites:=true; // change LazLogger to use non-buffered output
    if miEnableLCLDebug.checked then
    begin
      deletefile('cedebug.txt');

      llf.LogName:='cedebug.txt';
      llf.Init;


      DebugLn('First log message: '+DateToStr(now));
    end
    else
      llf.Finish;
  end;

  TraceExceptions:=miEnableLCLDebug.checked;

  miTriggerAccessViolation.visible:=TraceExceptions;
  miTestAccessViolationThread.visible:=TraceExceptions;

end;

procedure TMainForm.actOpenDissectStructureExecute(Sender: TObject);
var address: ptruint;
  i: integer;
  f: TfrmStructures2;
  found: boolean;
  c: TStructColumn;
begin

  if frmStructures2.count>0 then
  begin
    if addresslist.Focused and (addresslist.selectedRecord<>nil) and
       (not addresslist.selectedRecord.isGroupHeader or addresslist.selectedRecord.isAddressGroupHeader) and
       (addresslist.selectedRecord.VarType<>vtAutoAssembler)
    then
    begin
      //add this address if it's not yet in the list
      found:=false;

      address:=addresslist.selectedRecord.GetRealAddress;
      f:=TfrmStructures2(frmStructures2[0]);
      for i:=0 to f.columnCount-1 do
        if f.columns[i].Address=address then
        begin
          found:=true;
          f.columns[i].focus;
          break;
        end;

      if not found then
      begin
        c:=f.addColumn;
        c.Address:=address;
        c.focus;
      end;
    end;

    TfrmStructures2(frmStructures2[0]).show;
  end
  else
  begin
    //create it
    with tfrmstructures2.create(application) do
    begin
      //fill in the selected memoryrecord if there is one, else use the memoryview hexview address
      initialaddress:=MemoryBrowser.hexview.address;

      if (addresslist.selectedRecord<>nil) and
         (not addresslist.selectedRecord.isGroupHeader or addresslist.selectedRecord.isAddressGroupHeader) and
         (addresslist.selectedRecord.VarType<>vtAutoAssembler)
      then
        initialaddress:=addresslist.selectedRecord.GetRealAddress;

      show;
    end;
  end;
end;

procedure TMainForm.actOpenLuaEngineExecute(Sender: TObject);
begin
  MemoryBrowser.miLuaEngine.Click;
end;

procedure TMainForm.cbFastScanChange(Sender: TObject);
begin
  edtAlignment.Enabled := cbFastScan.Checked and cbfastscan.Enabled;
  rbFsmAligned.Enabled := edtAlignment.Enabled;
  rbfsmLastDigts.Enabled := edtAlignment.Enabled;

  alignsizechangedbyuser := False;
  VarType.OnChange(vartype);
end;


procedure TMainForm.CreateGroupClick(Sender: TObject);
var
  groupname: string;
  i: integer;
  Count: integer;
  withAddress: boolean;
begin
  //in rare cases you can use the treeview data data if you request so
  Count := 0;
  for i := 0 to addresslist.Items.Count - 1 do
    if TMemoryRecord(addresslist.Items[i].Data).isGroupHeader then
      Inc(Count);

  groupname := Format(rsGroup, [IntToStr(Count + 1)]);

  if InputQuery(rsGroups, rsWhatDoYouWantTheGroupnameToBe, groupname) then
  begin
    withAddress:=(messagedlg(rsDoYouWantTheGroupWithAddress, mtConfirmation, [mbYes, mbNo], 0)=mrYes);
    addresslist.CreateGroup(groupname, withAddress);
  end;
end;

procedure TMainForm.gbScanOptionsChangeBounds(Sender: TObject);
begin
  spawnBoundsUpdater;
end;

procedure TMainForm.Label3Click(Sender: TObject);
begin

end;


procedure triggerAV(AData : Pointer);
var p: pbyte;
begin
  p:=pbyte($ce);
  p^:=p^+$ce;

  beep;

end;

type TTestThread=class(tthread)
  procedure Execute; override;
end;


procedure TTestThread.Execute;
begin
  SetThreadDebugName(ThreadID,'Crashy thread');
  triggerav(nil);

end;

procedure TMainForm.miTestAccessViolationThreadClick(Sender: TObject);
var m: Tmethod;

  t: TTestthread;
begin
  t:=ttestthread.Create(true);


  //t.FreeOnTerminate:=true;
  t.Start;
  {
  while t.Finished=false do
    sleep(100);

  if t.FatalException=nil then
    showmessage('all ok')
  else
    showmessage('error');  }


end;

procedure TMainForm.miTriggerAccessViolationClick(Sender: TObject);
begin
  triggerAV(nil);
  showmessage('Weeee! Fuck You!');
end;


procedure TMainForm.MenuItem16Click(Sender: TObject);
{$ifdef darwin}
var p: TProcessUTF8;
  path: string;
{$endif}
begin
  {$ifdef darwin}
  p:=TProcessUTF8.Create(self);
  path:=ExtractFilePath(application.ExeName)+'tutorial-aarch64.app/Contents/MacOS/tutorial-aarch64';
  //OutputDebugString('path='+path);
  p.Executable:=(path);
  p.Execute;
  {$endif}
end;

procedure TMainForm.miClearWorkingSetClick(Sender: TObject);
begin
  {$ifdef windows}
  if assigned(EmptyWorkingSet) then
  begin
    if messagedlg(rsClearingMeansSlowness, mtInformation, [mbyes, mbno], 0)=
      mryes then
      EmptyWorkingSet(processhandle);
  end;
  {$endif}
end;

procedure TMainForm.miTutorial64Click(Sender: TObject);
{$ifdef darwin}
var p: TProcessUTF8;
  path: string;
{$endif}
begin
  {$ifdef darwin}
  p:=TProcessUTF8.Create(self);
  path:=ExtractFilePath(application.ExeName)+'tutorial-x86_64.app/Contents/MacOS/tutorial-x86_64';

  OutputDebugString('path='+path);
  p.Executable:=(path);
  p.Execute;
  {$else}
  shellexecute(0, 'open', pchar(cheatenginedir+{$ifdef altname}'rtmtutorial-x86_64.exe'{$else}'Tutorial-x86_64.exe'{$endif}), nil, nil, sw_show);
  {$endif}
end;

procedure TMainForm.MenuItem15Click(Sender: TObject);
var nexttut: string;
    filename: string;
begin
  filename:='gtutorial-'+{$ifdef cpu32}'i386'{$else}'x86_64'{$endif}+'.exe';
  nexttut:=ExtractFilePath(application.ExeName)+filename;

  if fileexists(nexttut) then
  begin
    //launch the graphical tutorial
    ShellExecute(0, PChar('open'), PChar(nexttut),PChar(''), PChar(extractfilepath(nexttut)), SW_SHOW);
    exit;
  end;


  nexttut:=ExtractFileDir(application.ExeName);

  if ExtractFileName(nexttut)='bin' then
  begin
    nexttut:=ExtractFilePath(nexttut)+'tutorial\graphical\'+filename;

    if fileexists(nexttut) then
    begin
      //launch the graphical tutorial
      ShellExecute(0, PChar('open'), PChar(nexttut),PChar(''), PChar(extractfilepath(nexttut)), SW_SHOW);
      exit;
    end;
  end;
end;



procedure TMainForm.miDeleteSavedScanResultsClick(Sender: TObject);
var
  s: tstringlist;
  l: TfrmSelectionList;
  i: integer;

  tobedeleted: string;
begin
  tobedeleted:='';
  s:=tstringlist.create;
  i:=memscan.getsavedresults(s);
  if i=1 then exit;


  s.Delete(0);
  l := TfrmSelectionList.Create(self, s);
  l.Caption := rsSavedScanResults;
  l.label1.Caption := rsSelectTheSavedScanResultFromTheListBelow;
  l.ItemIndex := 0;

  if (l.showmodal = mrOk) and (l.ItemIndex <> -1) then
    tobedeleted := l.selected;

  s.free;

  if compareToSavedScan and (currentlySelectedSavedResultname=tobedeleted) then
    cbCompareToSavedScan.checked:=false;

  if tobedeleted<>'' then
    memscan.deleteSavedResult(tobedeleted);

  reloadPreviousResults;
end;


procedure TMainForm.miFoundListPreferencesClick(Sender: TObject);
var
  f: TfrmFoundlistPreferences;
  reg: TRegistry;
begin
  f:=TfrmFoundlistPreferences.Create(self);

  f.Font.assign(foundlist3.font);
  f.NormalValueColor:=foundlistColors.NormalValueColor;
  f.ChangedValueColor:=foundlistColors.ChangedValueColor;
  f.BackgroundColor:=foundlist3.color;
  f.StaticColor:=foundlistColors.StaticColor;
  f.DynamicColor:=foundlistColors.DynamicColor;
  f.ShowStaticAsStatic:=showStaticAsStatic;
  f.CompareToHeaderColor:=foundlistColors.compareToHeadercolor;
  f.UseThisFontSize:=AddressListOverrideFontSize;
  if f.showmodal=mrok then
  begin
    foundlist3.font.Assign(f.font);
    foundlist3.Color:=f.BackgroundColor;

    foundlistColors.NormalValueColor:=f.NormalValueColor;
    foundlistColors.ChangedValueColor:=f.ChangedValueColor;
    foundlistColors.StaticColor:=f.StaticColor;
    foundlistColors.DynamicColor:=f.DynamicColor;
    foundlistcolors.compareToHeadercolor:=f.CompareToHeaderColor;;
    showStaticAsStatic:=f.ShowStaticAsStatic;
    AddressListOverrideFontSize:=f.UseThisFontSize;



    reg := Tregistry.Create;
    try
      Reg.RootKey := HKEY_CURRENT_USER;

      if Reg.OpenKey('\Software\'+strCheatEngine+'\FoundList'+darkmodestring, True) then
      begin
        reg.WriteInteger('FoundList.NormalValueColor', foundlistcolors.NormalValueColor);
        reg.WriteInteger('FoundList.ChangedValueColor', foundlistcolors.ChangedValueColor);
        reg.WriteInteger('FoundList.StaticColor', foundlistcolors.StaticColor);
        reg.WriteInteger('FoundList.DynamicColor', foundlistcolors.DynamicColor);
        reg.WriteInteger('FoundList.BackgroundColor',foundlist3.Color);
        reg.WriteInteger('FoundList.CompareToHeaderColor', foundlistcolors.CompareToHeaderColor);
        reg.WriteBool('FoundList.ShowStaticAsStatic',ShowStaticAsStatic);
        reg.WriteBool('FoundList.OverrideFontSize',AddressListOverrideFontSize);

        SaveFontToRegistry(foundlist3.font, reg);
      end;
    finally
      reg.free;
    end;
  end;

  f.free;


end;

procedure TMainForm.miAutoAssembleErrorMessageClick(Sender: TObject);
begin
  clipboard.AsText:=miAutoAssembleErrorMessage.Caption;
  addresslist.doValueChange;
end;

procedure TMainForm.miHelpClick(Sender: TObject);
begin
  miEnableLCLDebug.visible:=miEnableLCLDebug.checked or (ssCtrl in GetKeyShiftState);
end;

procedure TMainForm.miLuaDocumentationClick(Sender: TObject);
begin
  {$ifdef darwin}
  OpenDocument(pchar(ExtractFilePath(application.ExeName)+'../Lua/celua.txt'));
  {$else}
  ShellExecute(0,'open',pchar(ExtractFilePath(application.ExeName)+'celua.txt'),nil,nil,SW_SHOW);
  {$endif}

end;

procedure TMainForm.miForgotScanClick(Sender: TObject);
begin
  if (foundlist.count=0) or (memscan.lastScanWasRegionScan) then exit;

  cleanupPreviousResults;

  foundlist.Deinitialize; //unlock file handles

  if cbPauseWhileScanning.Checked then
  begin
    advancedoptions.Pausebutton.down := True;
    advancedoptions.Pausebutton.Click;
  end;

  ProgressBar.min := 0;
  ProgressBar.max := 1000;
  ProgressBar.position := 0;

  lastscantype := scantype.ItemIndex;
  memscan.nextscan(soForgot, rtRounded,'','', false, false,false,false,false,false,'');
  DisableGui;
  SpawnCancelButton;
end;


procedure TMainForm.miGetDotNetObjectListClick(Sender: TObject);
begin
  {$ifdef windows}
  if frmDotNetObjectList=nil then
    frmDotNetObjectList:=TfrmDotNetObjectList.create(self);

  frmDotNetObjectList.show;
  frmDotNetObjectList.loadlist;
  {$endif}
end;



procedure TMainForm.miSignTableClick(Sender: TObject);
begin
  {$ifdef windows}
  if Opendialog1.Execute then
    signTablefile(opendialog1.filename);
  {$endif}
end;

 {$ifdef windows}
var t: TRemoteMemoryManager;
  {$endif}

procedure TMainForm.miScanDirtyOnlyClick(Sender: TObject);
begin
  scan_dirtyonly:=miScanDirtyOnly.checked;
end;

procedure TMainForm.miCompressionClick(Sender: TObject);
begin
  {$ifdef windows}
  if frmNetworkDataCompression=nil then
    frmNetworkDataCompression:=tfrmNetworkDataCompression.create(self);

  frmNetworkDataCompression.show;
  {$endif}
end;


procedure TMainForm.miManualExpandCollapseClick(Sender: TObject);
begin
  miManualExpandCollapse.Checked := not miManualExpandCollapse.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miManualExpandCollapse.Checked then
      addresslist.selectedRecord.options :=
        addresslist.selectedRecord.options + [moManualExpandCollapse]
    else
      addresslist.selectedRecord.options :=
        addresslist.selectedRecord.options - [moManualExpandCollapse];
  end;
end;

procedure TMainForm.miSaveClick(Sender: TObject);
begin
  if fileexists(savedialog1.FileName) then
  begin
    savetable(savedialog1.FileName, false);

    recentFilesUpdate(savedialog1.filename);
  end
  else
    actSave.Execute;
end;

procedure TMainForm.mi3dClick(Sender: TObject);
begin
  {$ifdef windows}
  miHookD3D.checked:=(D3DHook<>nil) and (D3DHook.processid=processid);

  miLockMouseInGame.enabled:=miHookD3D.checked;
  miSetCrosshair.enabled:=miHookD3D.checked;

  if miHookD3D.checked=false then
    miLockMouseInGame.checked:=false;

  {$endif}
end;

procedure TMainForm.miChangeDisplayTypeClick(Sender: TObject);
begin
  //set the display type to override the default with
  foundlistDisplayOverride:=TMenuItem(sender).Tag;
  foundlist3.Refresh;
end;

procedure TMainForm.miOpenFileClick(Sender: TObject);
var
  oldprocess: Dword;
  resu: integer;
  oldprocesshandle: thandle;
  oldprocessname: string;
begin
  if not openprocessPrologue then
    exit;

  oldprocessname := copy(mainform.ProcessLabel.Caption, pos(
    '-', mainform.ProcessLabel.Caption) + 1, length(mainform.ProcessLabel.Caption));

  oldprocess := processID;
  oldprocesshandle := processhandle;

  if Processwindow = nil then
    ProcessWindow := TProcessWindow.Create(application);

  ProcessWindow.miOpenFile.click;

  if ProcessWindow.modalresult=mrOK then
    openProcessEpilogue(oldprocessname, oldprocess, oldprocesshandle);
end;

procedure TMainForm.miScanPagedOnlyClick(Sender: TObject);
begin
  scan_pagedonly:=miScanPagedOnly.checked;
end;

procedure TMainForm.miSetDropdownOptionsClick(Sender: TObject);
var f: TFrmMemoryRecordDropdownSettings;
  memrec: TMemoryRecord;
begin
  if addresslist.selectedrecord<>nil then
  begin
    memrec:=addresslist.SelectedRecord;
    //random text here
    f:=TFrmMemoryRecordDropdownSettings.create(memrec, addresslist);
    f.ShowModal;
  end;
end;


procedure TMainForm.miShowAsSignedClick(Sender: TObject);
var
  i: integer;
  newstate: boolean;
begin
  if addresslist.selectedRecord <> nil then
  begin
    newstate := not addresslist.selectedRecord.showAsSigned;

    for i := 0 to addresslist.Count - 1 do
      if addresslist[i].isSelected then
        addresslist[i].showAsSigned := newstate;
  end;

end;




procedure TMainForm.MenuItem1Click(Sender: TObject);
begin
  addresslist.SelectAll;
end;

procedure TMainForm.miShowLuaScriptClick(Sender: TObject);
begin
  frmLuaTableScript.Show;
end;

procedure TMainForm.miAddAddressClick(Sender: TObject);
begin
  SpeedButton3.Click;
end;

procedure TMainForm.miAllowCollapseClick(Sender: TObject);
begin
  miAllowCollapse.Checked := not miAllowCollapse.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miAllowCollapse.Checked then
      addresslist.selectedRecord.options := addresslist.selectedRecord.options + [moAllowManualCollapseAndExpand]
    else
      addresslist.selectedRecord.options := addresslist.selectedRecord.options - [moAllowManualCollapseAndExpand];
  end;
end;

procedure TMainForm.updated3dgui;
begin
  {$ifdef windows}
  miSetCrosshair.Enabled := d3dhook<>nil;
  miWireframe.Enabled := d3dhook<>nil;
  miZbuffer.Enabled := d3dhook<>nil;
  miLockMouseInGame.enabled := d3dhook<>nil;
  {$endif}
end;

procedure TMainForm.miHookD3DClick(Sender: TObject);
begin
  {$ifdef windows}
  if MessageDlg('Are you sure you wish to hook Direct3D?', mtConfirmation, [mbyes,mbno],0)=mryes then
  begin
    safed3dhook;
    updated3dgui;
  end;
  {$endif}
end;

procedure TMainForm.miSnapshothandlerClick(Sender: TObject);
begin
  {$ifdef windows}
  if frmSnapshotHandler=nil then
  begin
    frmSnapshotHandler:=tfrmSnapshotHandler.Create(application);
    frmSnapshotHandler.show;
    if D3DHook<>nil then
      frmSnapshotHandler.miConfig.click; //configure it if needed
  end
  else
    frmSnapshotHandler.show;
  {$endif}
end;

procedure TMainForm.miLockMouseInGameClick(Sender: TObject);
begin
  {$ifdef windows}
  safed3dhook;
  updated3dgui;

  if d3dhook<>nil then
    d3dhook.setMouseClip(miLockMouseInGame.checked);
  {$endif}
end;

procedure TMainForm.miPresetAllClick(Sender: TObject);
begin
  cbWritable.State := cbGrayed;
  cbCopyOnWrite.state := cbGrayed;
  cbExecutable.state := cbGrayed;
  {$ifdef darwin}
  cbDirty.state := cbGrayed;
  {$endif}

end;

procedure TMainForm.miAddFileClick(Sender: TObject);
var
  f: TOpendialog;

  lf: TLuafile;
  s: TMemorystream;
  i: integer;
begin
  f := TOpendialog.Create(self);
  try
    f.Options:=f.options+[ofAllowMultiSelect, ofFileMustExist];
    if f.Execute then
    begin
      s := TMemorystream.Create;

      for i:=0 to f.Files.Count-1 do
      begin
        s.clear;
        s.LoadFromFile(f.Files[i]);
        lf := TLuaFile.Create(extractfilename(f.files[i]), s);
        LuaFiles.add(lf);
      end;
      freeandnil(s);
    end;

  finally
    if f<>nil then
      freeandnil(f);
  end;
end;

procedure TMainForm.MenuItem9Click(Sender: TObject);

begin
  {$ifdef windows}
  if frmTrainerGenerator = nil then
    frmTrainerGenerator := tfrmTrainerGenerator.Create(self);

  if frmTrainerGenerator.canceled then
  begin
    frmTrainerGenerator.Close;
    exit;
  end;

  frmTrainerGenerator.Show;
  {$endif}
end;

procedure TMainForm.miPresetWritableClick(Sender: TObject);
begin
  cbWritable.State := cbchecked;
  cbCopyOnWrite.state := cbGrayed;
  cbExecutable.state := cbGrayed;
  {$ifdef darwin}
  cbDirty.state := cbGrayed;
  {$endif}
end;

procedure TMainForm.miResyncFormsWithLuaClick(Sender: TObject);
var
  i: integer;
begin
  for i := 0 to LuaForms.Count - 1 do
    TCEForm(LuaForms[i]).ResyncWithLua;

end;

procedure TMainForm.DeleteFormClick(Sender: TObject);
var
  f: tceform;
begin
  if messagedlg(rsAreYouSureYouWantToDeleteThisForm, mtConfirmation,
    [mbYes, mbNo], 0) = mrYes then
  begin
    if LuaForms.Count = 1 then //close the designerform when it's the last object
      if FormDesigner <> nil then
        FormDesigner.Close;


    f := TCEForm(LuaForms[TMenuItem(Sender).Tag]);
    f.Free;

    LuaForms.Delete(TMenuItem(Sender).Tag);

    UpdateMenu;

  end;
end;

procedure TMainForm.EditFormClick(Sender: TObject);
var
  f: tceform;
begin
  f := TCEForm(LuaForms[TMenuItem(Sender).Tag]);


  if formdesigner = nil then
    createFormdesigner;

  formdesigner.designForm(f);      //opendialog my .ss

  formdesigner.Show;

  f.Show;
end;

procedure TMainForm.RestoreAndShowFormClick(Sender: TObject);
var
  f: tceform;
begin
  f := TCEForm(LuaForms[TMenuItem(Sender).Tag]);
  if f.designsurface <> nil then
    f.designsurface.Active := False;

  f.RestoreToDesignState;
  f.Show;
end;

procedure TMainForm.FormDesignerClose(Sender: TObject; var CloseAction: TCloseAction);
var
  i: integer;
  f: TCEForm;
begin
  for i := 0 to LuaForms.Count - 1 do
  begin
    f := TCEForm(LuaForms[i]);
    f.Active := False;
    if f.designsurface <> nil then
      FreeAndNil(f.designsurface);
  end;

  closeAction := caFree;
  FormDesigner := nil;
end;


procedure TMainForm.RenameFileClick(Sender: TObject);
var
  lf: TLuafile;
  newname: string;
begin
  lf := LuaFiles[TMenuItem(Sender).Tag];
  newname:=lf.Name;
  InputQuery(rsRenameFile, rsGiveTheNewFilename, newname);

  if IsXmlName(newname, true) then
    lf.name:=newname
  else
    MessageDlg(Format(rsIsNotAValidX, [newname]), mtError, [mbok], 0);
end;

procedure TMainForm.SaveFileClick(Sender: TObject);
var
  lf: TLuafile;
  f: TSavedialog;
begin
  lf := LuaFiles[TMenuItem(Sender).Tag];

  f := tsavedialog.Create(self);
  try
    f.filename := lf.Name;
    if f.Execute then
      lf.stream.SaveToFile(f.filename);
  finally
    freeandnil(f);
  end;
end;

procedure TMainForm.DeleteFileClick(Sender: TObject);
var
  lf: TLuafile;
begin
  lf := LuaFiles[TMenuItem(Sender).Tag];
  LuaFiles.Delete(TMenuItem(Sender).Tag);

  lf.Free;
  UpdateMenu;

end;

procedure TMainForm.UpdateMenu;
var
  i: integer;
  mi: tmenuitem;
  f: tceform;
  lf: TLuafile;

  submenu: TMenuItem;

  m: tmemorystream;
  b: tbitmap;
begin
  miLuaFormsSeperator.Visible := True; //LuaForms.Count>0;


  while miTable.Count > 5 do
  begin
    if miTable.Items[4] <> miLuaFormsSeperator then
      miTable[4].Free
    else
      break;
  end;

  for i := 0 to LuaForms.Count - 1 do
  begin
    mi := tmenuitem.Create(miTable);

    f := tceform(LuaForms[i]);
    {
    //this currently won't work
    if f.icon<>nil then
    begin
      b:=tbitmap.create;
      b.Width := f.Icon.Width;
      b.Height := f.Icon.Height;
      b.Canvas.Draw(0, 0, f.Icon ) ;

      m:=tmemorystream.create;
      b.SaveToStream(m);
      m.position:=0;
      mi.Bitmap.LoadFromStream(m);
      m.free;
      b.free;
    end;}


    mi.Caption := f.Name;
    mi.ImageIndex:=16;
    miTable.Insert(4, mi);


    submenu := tmenuitem.Create(mi);
    submenu.Caption := rsRestoreAndShow;
    submenu.OnClick := @RestoreAndShowFormClick;
    submenu.Tag := i;
    submenu.Default := True;
    mi.Add(submenu);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := rsEdit;
    submenu.ImageIndex:=17;
    submenu.OnClick := @EditFormClick;
    submenu.Tag := i;
    mi.Add(submenu);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := '-';
    submenu.Tag := i;
    mi.Add(submenu);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := rsDelete;
    submenu.ImageIndex:=22;
    submenu.OnClick := @DeleteFormClick;
    submenu.Tag := i;
    mi.Add(submenu);
  end;


  //and now the files
  while miTable.Count > miTable.indexOf(miAddFile) + 1 do
    miTable[miTable.indexOf(miAddFile) + 1].free;

  for i := 0 to luafiles.Count - 1 do
  begin
    mi := tmenuitem.Create(miTable);
    lf := luafiles[i];
    mi.Caption := lf.Name;

    miTable.add(mi);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := rsRename;
    submenu.ImageIndex:=17;
    submenu.OnClick := @RenameFileClick;
    submenu.Tag := i;
    mi.Add(submenu);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := rsSaveToDisk;
    submenu.ImageIndex:=4;
    submenu.OnClick := @SaveFileClick;
    submenu.Tag := i;
    mi.Add(submenu);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := '-';
    mi.Add(submenu);

    submenu := tmenuitem.Create(mi);
    submenu.Caption := rsDelete;
    submenu.ImageIndex:=22;
    submenu.OnClick := @DeleteFileClick;
    submenu.Tag := i;
    mi.Add(submenu);

  end;

end;

procedure TMainForm.createFormdesigner;
begin
  if FormDesigner = nil then
  begin
    FormDesigner := TFormDesigner.Create(self);
    formdesigner.autosize := False;
    FormDesigner.OnClose2 := @FormDesignerClose;
  end;
end;

procedure TMainForm.miCreateLuaFormClick(Sender: TObject);
var
  f: tceform;
  i, j, k: integer;

  s: string;

  br: TRect;
begin
  f := tceform.CreateNew(nil);
  f.DesignTimePPI:=screen.PixelsPerInch;
  f.autosize := False;

  j := 1;
  //found out a unique name for this form
  for i := 0 to LuaForms.Count - 1 do
  begin
    s := copy(tceform(LuaForms[i]).Name, 1, 3);
    if s = 'UDF' then
    begin
      s := tceform(LuaForms[i]).Name;
      s := copy(s, 4, length(s));
      if TryStrToInt(s, k) then
      begin
        if k >= j then
          j := k + 1;
      end;
    end;
  end;


  f.Name := 'UDF' + IntToStr(j);
  luaforms.add(f);




  if formdesigner = nil then
    createFormdesigner;

  formdesigner.designForm(f);

  formdesigner.Show;

  f.clientwidth:=ScaleX(200,96);
  f.clientheight:=ScaleY(200,96);

  f.Show;

  f.left := formdesigner.left;

  LCLIntf.GetWindowRect(formdesigner.handle, br);
  f.top := br.Bottom + 5;

  updatemenu;
end;

procedure TMainForm.MenuItem7Click(Sender: TObject);
begin
  Close;
end;

procedure TMainForm.miSetCrosshairClick(Sender: TObject);
begin
  {$ifdef windows}
  if frmSetCrosshair = nil then
    frmSetCrosshair := TfrmSetCrosshair.Create(self);

  frmSetCrosshair.Show;
  {$endif}
end;

procedure TMainForm.miTableClick(Sender: TObject);
begin
  UpdateMenu;
end;

procedure TMainForm.miResetRangeClick(Sender: TObject);
begin
  {$ifdef cpu64}
  FromAddress.Text := '0000000000000000';
  ToAddress.Text := '00007fffffffffff';
  {$else}
  FromAddress.Text := '00000000';
  if Is64bitOS then
    ToAddress.Text := 'ffffffff' //games with 3GB aware will use this in 64-bit os's
  else
    ToAddress.Text := '7fffffff';
  {$endif}
end;

procedure TMainForm.miChangeColorClick(Sender: TObject);
var
  i: integer;
begin
  if (addresslist.SelCount > 0) then
  begin
    colordialog1.Color:=addresslist.selectedRecord.Color;
    if (colordialog1.Execute) then
      for i := 0 to addresslist.Count - 1 do
        if addresslist[i].isSelected then
          addresslist[i].color := colordialog1.Color;
  end;
end;




procedure TMainForm.miBindActivationClick(Sender: TObject);
begin
  miBindActivation.Checked := not miBindActivation.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miBindActivation.Checked then
      addresslist.selectedRecord.options := addresslist.selectedRecord.options + [moActivateChildrenAsWell]
    else
      addresslist.selectedRecord.options := addresslist.selectedRecord.options - [moActivateChildrenAsWell];
  end;
end;

procedure TMainForm.miBindDeactivationClick(Sender: TObject);
begin
  miBindDeactivation.Checked := not miBindDeactivation.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miBindDeactivation.Checked then
      addresslist.selectedRecord.options := addresslist.selectedRecord.options + [moDeactivateChildrenAsWell]
    else
      addresslist.selectedRecord.options := addresslist.selectedRecord.options - [moDeactivateChildrenAsWell];
  end;
end;

procedure TMainForm.miDisassembleClick(Sender: TObject);
begin
  if addresslist.selectedrecord <> nil then
  begin
    memorybrowser.disassemblerview.SelectedAddress := addresslist.selectedrecord.GetRealAddress;
    memorybrowser.Show;
  end;
end;





procedure TMainForm.miHideChildrenClick(Sender: TObject);
begin
  miHideChildren.Checked := not miHideChildren.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miHideChildren.Checked then
      addresslist.selectedRecord.options :=
        addresslist.selectedRecord.options + [moHideChildren]
    else
      addresslist.selectedRecord.options :=
        addresslist.selectedRecord.options - [moHideChildren];
  end;
end;

procedure TMainForm.setGbScanOptionsEnabled(state: boolean);
procedure setstaterecursive(c: TWinControl);
var i: integer;
begin
  c.enabled:=state;
  for i:=0 to c.ControlCount-1 do
  begin
    if (c.Controls[i] is TWinControl) then
      setstaterecursive(twincontrol(c.controls[i]))
    else
      c.controls[i].enabled:=state;
  end;

end;
begin
  setstaterecursive(gbScanOptions);
end;

procedure TMainForm.LoadCustomTypesFromRegistry;
var
  reg: TRegistry;
  customtypes: TStringList;
  i: integer;
  islua: boolean;
  oldpos: integer;
begin
  reg := tregistry.Create;
  oldpos:=vartype.ItemIndex;
  vartype.OnChange := nil;
  //disable the onchange event so CreateCustomType doesn't keep setting it
  try
    if reg.OpenKey('\Software\'+strCheatEngine+'\CustomTypes\', False) then
    begin
      CustomTypes := TStringList.Create;
      try
        reg.GetKeyNames(CustomTypes);

        for i := 0 to CustomTypes.Count - 1 do
        begin
          if reg.OpenKey('\Software\'+strCheatEngine+'\CustomTypes\' + CustomTypes[i], False) then
          begin
            try
              islua := False;
              if reg.ValueExists('lua') then
                islua := reg.ReadBool('lua');

              CreateCustomType(nil, reg.ReadString('Script'), True, islua);
            except
              outputdebugstring('The custom type script ''' + CustomTypes[i] +
                ''' could not be loaded');
            end;
          end;
        end;

      except
        //empty customtype
      end;
      freeandnil(CustomTypes);
    end;
    freeandnil(reg);
    RefreshCustomTypes;
  finally
    vartype.itemindex:=oldpos;
    vartype.OnChange := @VarTypeChange;   //set the onchange event back
  end;
end;

procedure TMainForm.RefreshCustomTypes;
{
In short: remove all custom scan types and add them back
}
var
  i: integer;
begin
  vartype.items.BeginUpdate;
  try
    while VarType.Items.Count > 11 do
      vartype.items.Delete(11);


    for i := 0 to customTypes.Count - 1 do
      vartype.Items.AddObject(TCustomType(customTypes[i]).Name, tobject(customTypes[i]));

    //set to default (4 bytes) if not selected anything anymore
    if (vartype.ItemIndex = -1) or (vartype.ItemIndex >= VarType.Items.Count) then
      vartype.ItemIndex := 3;


  finally
    vartype.items.EndUpdate;
  end;

  vartype.DropDownCount := vartype.items.Count;

  addresslist.refreshcustomtypes;
end;

procedure TMainForm.miDeleteCustomTypeClick(Sender: TObject);
var
  reg: TRegistry;
  ct: TCustomType;
begin
  ct := TCustomType(vartype.Items.Objects[vartype.ItemIndex]);
  if (ct <> nil) and ((ct.CustomTypeType = cttAutoAssembler) or
    (ct.CustomTypeType = cttLuaScript)) then
  begin
    if messagedlg(Format(rsAreYouSureYouWantToDelete, [ct.Name]),
      mtConfirmation, [mbNo, mbYes], 0) = mrYes then
    begin
      reg := tregistry.Create;
      reg.DeleteKey('\Software\'+strCheatEngine+'\CustomTypes\' + ct.Name);
      ct.remove;
      RefreshCustomTypes;
    end;
  end;
end;

procedure TMainForm.CreateCustomType(customtype: TCustomtype;
  script: string; scriptchanged: boolean; lua: boolean = False);
var
  reg: TRegistry;
  ct: TCustomType;
  oldname: string;
  i: integer;
begin

  ct := nil;
  if scriptchanged then
  begin
    if customtype = nil then
    begin
      if not lua then
        ct := TCustomType.CreateTypeFromAutoAssemblerScript(script)
      else
        ct := TcustomType.CreateTypeFromLuaScript(script);
    end
    else
    begin
      //edited script

      ct := customtype;
      oldname := ct.Name;
      ct.setScript(script, lua);

      //if the new script has a different name then delete the old one
      if oldname <> ct.Name then
      begin
        //delete the old one
        reg := Tregistry.Create;
        reg.DeleteKey('\Software\'+strCheatEngine+'\CustomTypes\' + oldname);
        freeandnil(reg);
      end;
    end;



    //Add/change this to the registry
    reg := Tregistry.Create;
    if Reg.OpenKey('\Software\'+strCheatEngine+'\CustomTypes\' + ct.Name, True) then
    begin
      reg.WriteString('Script', script);
      if lua then
        reg.WriteBool('lua', True);

    end;

    freeandnil(reg);

    RefreshCustomTypes;

    //now set the type to the current type
    if (ct <> nil) then
    begin
      for i := 0 to vartype.Items.Count - 1 do
        if TCustomType(vartype.items.objects[i]) = ct then
        begin
          vartype.ItemIndex := i;
          if assigned(vartype.OnChange) then  //force an onchange (lazarus bug)
            vartype.OnChange(vartype);
          break;
        end;
    end;

  end;
end;



procedure TMainForm.miEditCustomTypeClick(Sender: TObject);
var
  ct: TCustomType;
begin
  ct := TCustomType(vartype.Items.Objects[vartype.ItemIndex]);
  if (ct <> nil) and ((ct.CustomTypeType = cttAutoAssembler) or
    (ct.CustomTypeType = cttLuaScript)) then
  begin

    with TfrmAutoInject.Create(self) do
    begin
      injectintomyself := True;
      CustomTypeScript := True;
      CustomTypeCallback := @CreateCustomType;
      CustomType := ct;
      if ct.CustomTypeType = cttLuaScript then
        ScriptMode :=smLua;

      assemblescreen.Lines.Text := CustomType.script;

      Show;
    end;

  end;
end;


procedure TMainForm.miDefineNewCustomTypeLuaClick(Sender: TObject);
var
  fbn, n: string;
begin
  n := 'Custom LUA type';
  fbn := 'customvaluetype';
  if customTypes.Count > 0 then
  begin
    n := n + ' ' + IntToStr(customtypes.Count + 1);
    fbn := fbn + IntToStr(customtypes.Count + 1);
  end;

  with TfrmAutoInject.Create(self) do
  begin
    injectintomyself := True;
    CustomTypeScript := True;
    CustomTypeCallback := @CreateCustomType;
    CustomType := nil;
    ScriptMode:= smLua;

    with assemblescreen.Lines do
    begin
      Add('--Note: keep the function base name unique.');
      Add('local typename="' + n + '" --shown as the typename in ce');
      Add('local bytecount=4  --number of bytes of this type');
      Add('local functionbasename="' + fbn + '"');
      Add('local usesfloat=false');
      Add('local usesstring=false');
      Add('');
      Add('function ' + fbn + '_bytestovalue(b1,b2,b3,b4,address)');
      Add('--Add extra byte parameters as required');
      Add('return 123');
      Add('');
      Add('end');
      Add('');
      Add('function ' + fbn + '_valuetobytes(i,address)');
      Add('');
      Add('--return the bytes to write (usually only used when you change the value)');
      Add('return 0,0,0,0');
      Add('');
      Add('end');
      Add('return typename, bytecount, functionbasename, usesfloat, usesstring');
    end;
    Show;

  end;
end;


procedure TMainForm.miDefineNewCustomTypeClick(Sender: TObject);
var
  fbn, n: string;
begin
  n := 'Custom Type Name';
  if customTypes.Count > 0 then
    n := n + ' ' + IntToStr(customtypes.Count + 1);

  with TfrmAutoInject.Create(self) do
  begin
    injectintomyself := True;
    CustomTypeScript := True;
    CustomTypeCallback := @CreateCustomType;
    CustomType := nil;

    with assemblescreen.Lines do
    begin
      Add('alloc(ConvertRoutine,1024)');
      Add('alloc(ConvertBackRoutine,1024)');
      Add('alloc(TypeName,256)');
      Add('alloc(ByteSize,4)');
      Add('alloc(UsesFloat,1)');
      Add('alloc(UsesString,1)');
      Add('alloc(MaxStringSize,2)');
      Add('alloc(CallMethod,1)');
      Add('');
      Add('TypeName:');
      Add('db ''' + n + ''',0');
      Add('');
      Add('ByteSize:');
      Add('dd 4');
      Add('');
      Add('UsesFloat:');
      Add('db 0 //Change to 1 if this custom type should be treated as a float');
      Add('');
      Add('UsesString:');
      Add('db 0');
      Add('');
      Add('MaxStringSize:');
      Add('dw #100');
      Add('');
      Add('CallMethod:');
      Add('db 1 //Remove or change to 0 for legacy call mechanism');
      Add('');
      Add('//The convert routine should hold a routine that converts the data to an integer (in eax)');
      Add('//function declared as: cdecl int ConvertRoutine(unsigned char *input, PTR_UINT address);');
      Add('//Note: Keep in mind that this routine can be called by multiple threads at the same time.');
      Add('ConvertRoutine:');
      Add('//jmp dllname.functionname');
      add('[64-bit]');
      Add('//or manual:');
      Add('//parameters: (64-bit)');
      {$ifdef windows}
      Add('//rcx=address of input');
      Add('//rdx=address');
      Add('mov eax,[rcx] //eax now contains the bytes ''input'' pointed to');
      {$else}
      Add('//rdi=address of input');
      Add('//rsi=address');
      Add('mov eax,[rdi] //eax now contains the bytes ''input'' pointed to');
      {$endif}
      Add('');
      Add('ret');
      add('[/64-bit]');
      add('');
      {$ifndef darwin}
      add('[32-bit]');
      Add('//jmp dllname.functionname');
      Add('//or manual:');
      Add('//parameters: (32-bit)'); //[esp]=return [esp+4]=input
      Add('push ebp');  //[esp]=ebp , [esp+4]=return [esp+8]=input
      Add('mov ebp,esp');  //[ebp]=ebp , [esp+4]=return [esp+8]=input
      Add('//[ebp+8]=address of input');
      Add('//[ebp+c]=address');
      Add('//example:');
      Add('mov eax,[ebp+8] //place the address that contains the bytes into eax');
      Add('mov eax,[eax] //place the bytes into eax so it''s handled as a normal 4 byte value');
      Add('');
      Add('pop ebp');
      Add('ret');
      add('[/32-bit]');
      {$endif}

      Add('');
      Add('//The convert back routine should hold a routine that converts the given integer back to a row of bytes (e.g when the user wats to write a new value)');
      Add('//function declared as: cdecl void ConvertBackRoutine(int i, PTR_UINT address, unsigned char *output);');
      Add('ConvertBackRoutine:');
      Add('//jmp dllname.functionname');
      Add('//or manual:');
      Add('[64-bit]');
      Add('//parameters: (64-bit)');
      {$ifdef windows}
      Add('//ecx=input (integer)');
      Add('//rdx=address');
      Add('//r8=address of output');
      Add('//example:');
      Add('mov [r8],ecx //place the integer at the 4 bytes pointed to by r8');
      {$else}
      Add('//edi=input (integer)');
      Add('//rsi=address');
      Add('//rdx=address of output');
      Add('//example:');
      Add('mov [rsi],edi //place the integer at the 4 bytes pointed to by rdx');
      {$endif}

      Add('');
      Add('ret');
      Add('[/64-bit]');
      add('');
{$ifndef darwin}
      Add('[32-bit]');
      Add('//parameters: (32-bit)'); //[esp]=return [esp+4]=input
      Add('push ebp');  //[esp]=ebp , [esp+4]=return [esp+8]=input
      Add('mov ebp,esp');  //[ebp]=ebp , [esp+4]=return [esp+8]=input
      Add('//[ebp+8]=input');
      Add('//[ebp+c]=address');
      Add('//[ebp+10]=address of output');
      Add('//example:');
      Add('push eax');
      Add('push ebx');
      Add('mov eax,[ebp+8] //load the value into eax');
      Add('mov ebx,[ebp+10] //load the output address into ebx');
      Add('mov [ebx],eax //write the value into the address');
      Add('pop ebx');
      Add('pop eax');

      Add('');
      Add('pop ebp');
      Add('ret');
      add('[/32-bit]');
{$endif}
      Add('');
    end;

    Show;
  end;

end;

procedure TMainForm.miRecursiveSetValueClick(Sender: TObject);
begin
  miRecursiveSetValue.Checked := not miRecursiveSetValue.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miRecursiveSetValue.Checked then
      addresslist.selectedRecord.options :=
        addresslist.selectedRecord.options + [moRecursiveSetValue]
    else
      addresslist.selectedRecord.options :=
        addresslist.selectedRecord.options - [moRecursiveSetValue];
  end;
end;

procedure TMainForm.miRenameTabClick(Sender: TObject);
var
  s: string;
begin
  s := scantablist.TabText[scantablist.SelectedTab];
  if InputQuery(rsCheatEngine, rsWhatWillBeTheNewNameForThisTab, s) then
    scantablist.TabText[scantablist.SelectedTab] := s;
end;



procedure TMainForm.SaveCurrentState(scanstate: PScanState; skipuservalues: boolean=false);
begin
  //save the current state
  scanstate^.alignsizechangedbyuser := alignsizechangedbyuser;

  scanstate^.compareToSavedScan := comparetosavedscan;
  scanstate^.currentlySelectedSavedResultname := currentlySelectedSavedResultname;
  scanstate^.compareToColumn := ActivePreviousResultColumn;

  scanstate^.cbCompareToSavedScan.visible := cbCompareToSavedScan.Visible;

  scanstate^.lblcompareToSavedScan.Caption := lblcompareToSavedScan.Caption;
  scanstate^.lblcompareToSavedScan.Visible := lblcompareToSavedScan.Visible;



  if not skipuservalues then
  begin
    scanstate^.FromAddress.Text := fromaddress.Text;
    scanstate^.ToAddress.Text := toaddress.Text;
  end;


  scanstate^.cbfastscan.Checked := cbFastScan.Checked;

  if not skipuservalues then
    scanstate^.edtAlignment.Text := edtAlignment.Text;

  scanstate^.edtAlignment.enabled:=edtAlignment.enabled;

  scanstate^.rbFsmAligned.checked:=rbFsmAligned.checked;

  if not skipuservalues then
    scanstate^.scanvalue.Text := scanvalue.Text;

  scanstate^.scanvalue.Visible := scanvalue.Visible;

  if scanvalue2 <> nil then
  begin
    scanstate^.scanvalue2.exists := True;
    if not skipuservalues then
      scanstate^.scanvalue2.Text := scanvalue2.Text;
  end
  else
    scanstate^.scanvalue2.exists := False;

  scanstate^.scantype.options := scantype.Items.Text;
  scanstate^.scantype.Enabled := scantype.Enabled;
  scanstate^.scantype.ItemIndex := scantype.ItemIndex;
  scanstate^.scantype.dropdowncount := scantype.DropDownCount;

  //scanstate^.vartype.options := vartype.Items;
  scanstate^.vartype.Enabled := vartype.Enabled;
  scanstate^.vartype.ItemIndex := vartype.ItemIndex;


  scanstate^.firstscanstate.Caption := btnNewScan.Caption;
  scanstate^.firstscanstate.Enabled := btnNewScan.Enabled;
  scanstate^.nextscanstate.Enabled := btnNextScan.Enabled;


  scanstate^.gbScanOptionsEnabled := gbScanOptions.Enabled;

  scanstate^.floatpanel.Visible := pnlfloat.Visible;
  scanstate^.floatpanel.rounded := rt1.Checked;
  scanstate^.floatpanel.roundedextreme := rt2.Checked;
  scanstate^.floatpanel.truncated := rt3.Checked;


  scanstate^.rbbit.Visible := rbbit.Visible;
  scanstate^.rbbit.Enabled := rbbit.Enabled;
  scanstate^.rbbit.Checked := rbbit.Checked;

  scanstate^.rbdec.Visible := rbdec.Visible;
  scanstate^.rbdec.Enabled := rbdec.Enabled;
  scanstate^.rbdec.Checked := rbdec.Checked;

  scanstate^.cbHexadecimal.Visible := cbHexadecimal.Visible;
  scanstate^.cbHexadecimal.Checked := cbHexadecimal.Checked;
  scanstate^.cbHexadecimal.Enabled := cbHexadecimal.Enabled;

  scanstate^.cbunicode.Visible := cbunicode.visible;
  scanstate^.cbunicode.checked := cbunicode.checked;

  scanstate^.cbRepeatUntilStopped.visible:=cbRepeatUntilStopped.visible;
  scanstate^.cbRepeatUntilStopped.checked:=cbRepeatUntilStopped.Checked;

  scanstate^.cbcodepage.Visible := cbcodepage.visible;
  scanstate^.cbcodepage.checked := cbcodepage.checked;
  scanstate^.cbCaseSensitive.Visible := cbCaseSensitive.visible;
  scanstate^.cbCaseSensitive.checked := cbCaseSensitive.checked;
  scanstate^.cbNot.visible:=cbNot.visible;
  scanstate^.cbnot.checked:=cbNot.checked;
  scanstate^.cbLuaformula.visible:=cbLuaFormula.Visible;
  scanstate^.cbLuaformula.checked:=cbLuaFormula.Checked;
  scanstate^.cbNewLuaState.visible:=cbNewLuaState.Visible;
  scanstate^.cbNewLuaState.checked:=cbNewLuaState.checked;

  if cbpercentage <> nil then
  begin
    scanstate^.cbpercentage.exists := False;
    scanstate^.cbpercentage.Checked := cbpercentage.Checked;
  end
  else
    scanstate^.cbpercentage.exists := False;

  scanstate^.btnFirst.tag := btnFirst.tag;
  scanstate^.foundlist3.ItemIndex := foundlist3.ItemIndex;

  scanstate^.foundlistDisplayOverride:=foundlistDisplayOverride;

  scanstate^.cbNot.Checked:=cbNot.checked;
  scanstate^.cbfloatSimple.Checked:=cbFloatSimple.checked


{
  if foundlist3.TopItem<>nil then
    scanstate^.foundlist3.topitemindex:=foundlist3.topitem.Index
  else
    scanstate^.foundlist3.topitemindex:=-1;    }
end;

procedure TMainForm.SetupInitialScanTabState(scanstate: PScanState;
  IsFirstEntry: boolean);
begin
  ZeroMemory(scanstate, sizeof(TScanState));

  if IsFirstEntry then
  begin
    scanstate^.memscan := memscan;
    scanstate^.foundlist := foundlist;
  end
  else
  begin
    scanstate^.memscan := tmemscan.Create(ProgressBar);
    scanstate^.memscan.GuiScanner:=true;
    scanstate^.memscan.OnGuiUpdate:=@MemscanGuiUpdate;
    scanstate^.foundlist := TFoundList.Create(foundlist3, scanstate^.memscan);    //build again
    scanstate^.memscan.OnInitialScanDone:=memscan.OnInitialScanDone;
    scanstate^.memscan.OnScanDone:=memscan.OnScanDone;
    scanstate^.memscan.OnScanStart:=memscan.OnScanStart;
  end;

  savecurrentstate(scanstate);
  reloadPreviousResults;
  ActivePreviousResultColumn:=2;
end;

procedure TMainForm.ScanTabListTabChange(Sender: TObject; oldselection: integer);
var
  oldstate, newstate: PScanState;
begin
  oldstate := scantablist.TabData[oldselection];
  newstate := scantablist.TabData[scantablist.SelectedTab];

  savecurrentstate(oldstate);

  //load the new state
  if newstate <> nil then
  begin
    //load
    mainform.BeginFormUpdate;
    foundlist3.beginupdate;
    foundlist.Deinitialize;

    foundlistDisplayOverride:=0;

    scantype.OnChange := nil;
    vartype.onchange := nil;
    rbbit.OnClick := nil;
    rbdec.Onclick := nil;
    cbHexadecimal.OnClick := nil;

    //cleanupPreviousResults;



    scanvalue.Text := newstate^.scanvalue.Text;
    scanvalue.Visible := newstate^.scanvalue.Visible;

    if newstate^.scanvalue2.exists then
    begin
      CreateScanValue2;
      scanvalue2.Text := newstate^.scanvalue2.Text;
    end
    else
    begin
      //destroy if it exists
      DestroyScanValue2;
    end;

    alignsizechangedbyuser := newstate^.alignsizechangedbyuser;
    comparetosavedscan := newstate^.compareToSavedScan;
    currentlySelectedSavedResultname := newstate^.currentlySelectedSavedResultname;
    //I love long variable names

    cbCompareToSavedScan.visible := newstate^.cbCompareToSavedScan.visible;

    lblcompareToSavedScan.Caption := newstate^.lblcompareToSavedScan.Caption;
    lblcompareToSavedScan.Visible := newstate^.lblcompareToSavedScan.Visible;


    scantype.items.Text := newstate^.scantype.options;
    scantype.Enabled := newstate^.scantype.Enabled;
    scantype.ItemIndex := newstate^.scantype.ItemIndex;
    scantype.DropDownCount := newstate^.scantype.dropdowncount;

   // vartype.items.Text := newstate^.vartype.options;
    vartype.Enabled := newstate^.vartype.Enabled;
    vartype.ItemIndex := newstate^.vartype.ItemIndex;


    btnNewScan.Caption := newstate^.firstscanstate.Caption;
    btnNewScan.Enabled := newstate^.firstscanstate.Enabled;

    btnNextScan.Enabled := newstate^.nextscanstate.Enabled;

    setGbScanOptionsEnabled(newstate^.gbScanOptionsEnabled);

    cbFastScan.OnChange:=nil;
    cbFastScan.Checked := newstate^.cbfastscan.Checked;
    cbFastScan.OnChange:=@cbFastScanChange;

    edtAlignment.Text := newstate^.edtAlignment.Text;
    edtAlignment.Enabled:=newstate^.edtAlignment.enabled;
    rbFsmAligned.checked:=newstate^.rbFsmAligned.checked;
    if rbFsmAligned.checked=false then
      rbfsmLastDigts.checked:=true;


    pnlfloat.Visible := newstate^.floatpanel.Visible;
    rt1.Checked := newstate^.floatpanel.rounded;
    rt2.Checked := newstate^.floatpanel.roundedextreme;
    rt3.Checked := newstate^.floatpanel.truncated;





    rbbit.Visible := newstate^.rbbit.Visible;
    rbbit.Enabled := newstate^.rbbit.Enabled;
    rbbit.Checked := newstate^.rbbit.Checked;

    rbdec.Visible := newstate^.rbdec.Visible;
    rbdec.Enabled := newstate^.rbdec.Enabled;
    rbdec.Checked := newstate^.rbdec.Checked;

    cbHexadecimal.Visible := newstate^.cbHexadecimal.Visible;
    cbHexadecimal.Checked := newstate^.cbHexadecimal.Checked;
    cbHexadecimal.Enabled := newstate^.cbHexadecimal.Enabled;

    if newstate^.cbpercentage.exists then
    begin
      CreateCbPercentage;
      cbpercentage.Checked := newstate^.cbpercentage.Checked;
    end
    else
      DestroyCbPercentage;

    btnFirst.tag := newstate^.btnFirst.tag;

    scantype.OnChange := @ScanTypeChange;
    VarType.OnChange := @VarTypeChange;
    rbbit.OnClick := @rbBitClick;
    rbdec.Onclick := @rbDecClick;
    cbHexadecimal.OnClick := @cbHexadecimalClick;








    memscan := newstate^.memscan;
    foundlist := newstate^.foundlist;


    if VarType.itemindex=10 then
    begin
      createGroupConfigButton;
      scantype.Visible:=false;
      lblscantype.Visible:=false;
    end
    else
    begin
      destroyGroupConfigButton;
      scantype.Visible:=true;
      lblscantype.Visible:=true;
    end;

    UpdateScanType;



    foundcount := foundlist.Initialize(getvartype, memscan.customtype);


    cbunicode.Visible := newstate^.cbunicode.visible;
    cbunicode.checked := newstate^.cbunicode.checked;
    cbCodePage.Visible := newstate^.cbCodePage.visible;
    cbCodePage.checked := newstate^.cbCodePage.checked;
    cbCaseSensitive.Visible := newstate^.cbCaseSensitive.visible;
    cbCaseSensitive.checked := newstate^.cbCaseSensitive.checked;


    cbRepeatUntilStopped.visible:=newstate^.cbRepeatUntilStopped.visible;
    cbRepeatUntilStopped.Checked:=newstate^.cbRepeatUntilStopped.checked;
    cbNot.visible:=newstate^.cbNot.visible;
    cbNot.checked:=newstate^.cbNot.Checked;
    cbLuaFormula.visible:=newstate^.cbLuaformula.visible;
    cbLuaFormula.checked:=newstate^.cbLuaformula.checked;
    cbNewLuaState.visible:=newstate^.cbNewLuaState.visible;
    cbNewLuaState.Checked:=newstate^.cbNewLuaState.checked;

    if newstate^.foundlist3.ItemIndex=-1 then
      newstate^.foundlist3.ItemIndex:=0;

    if (newstate^.foundlist3.ItemIndex < foundcount) then
    begin
      foundlist3.multiselect:=false;   //laz2.0.0: If multiselect is true when itemindex gets set ALL entries get deselected one by one (+each one triggering ondata)
      foundlist3.ItemIndex := newstate^.foundlist3.ItemIndex;
      foundlist3.Items[newstate^.foundlist3.ItemIndex].Selected := True;
      foundlist3.Items[newstate^.foundlist3.ItemIndex].MakeVisible(False);
      foundlist3.Items[newstate^.foundlist3.ItemIndex].Top := 0;
      foundlist3.multiselect:=true;
    end;



    foundlistDisplayOverride:=newstate^.foundlistDisplayOverride;

    cbNot.Checked:=newstate^.cbNot.checked;
    cbFloatSimple.checked:=newstate^.cbfloatSimple.Checked;

    UpdateFloatRelatedPositions;

    reloadPreviousResults;
    ActivePreviousResultColumn:=newstate^.compareToColumn;

   // Panel5Resize(nil);
    foundlist3.endupdate;

    mainform.EndFormUpdate;

    //    foundlist3.TopItem:=foundlist3.items[newstate^.foundlist.itemindex];
  end;
  //else leave empty
end;

procedure TMainForm.miAddTabClick(Sender: TObject);
var
  i: integer;
  c: array of tcontrol;
  foundlistheightdiff: integer;
  newstate: PScanState;

  scantabtopcontrol: TControl;
begin
  if scantablist = nil then
  begin
    foundlistheightdiff := btnMemoryView.top - (foundlist3.top + foundlist3.Height);

    scantablist := TTablist.Create(self);
    scantablist.Name:='ScantabList';

    scantabtopcontrol:=panel7;
    if scantabtopcontrol.top+scantabtopcontrol.Height<ProgressBar.Top+ProgressBar.Height then
      scantabtopcontrol:=ProgressBar;

    scantablist.AnchorSideTop.Control:=scantabtopcontrol;
    scantablist.AnchorSideTop.Side:=asrBottom;

    scantablist.AnchorSideLeft.Control:=panel5;
    scantablist.AnchorSideLeft.Side:=asrLeft;

    scantablist.AnchorSideRight.Control:=logopanel;
    if scantabtopcontrol.Top+scantabtopcontrol.Height<(logopanel.Height-4) then
      scantablist.AnchorSideRight.Side:=asrLeft
    else
      scantablist.AnchorSideRight.Side:=asrRight; //it can go under the logo

    scantablist.BorderSpacing.Top:=4;


    scantablist.PopupMenu := pmTablist;
    scantablist.color := panel5.GetRGBColorResolvingParent; //Color;
    scantablist.Parent:=panel5;
    scantablist.Anchors := [akTop, akLeft, akRight];

    scantablist.Height := scantablist.Canvas.TextHeight('WwJjDdQq')+4;

    label6.AnchorSideTop.Control:=scantablist;


    //lblcompareToSavedScan.AnchorSideTop.Control:=scantablist;


    i := scantablist.AddTab(rsScan + ' 1'); //original scan

    getmem(newstate, sizeof(TScanState));
    SetupInitialScanTabState(newstate, True);
    scantablist.TabData[i] := newstate;

    i := scantablist.AddTab(rsScan + ' 2'); //first new scan
    getmem(newstate, sizeof(TScanState));
    SetupInitialScanTabState(newstate, False);
    scantablist.TabData[i] := newstate;

    scantablist.OnTabChange := @ScanTabListTabChange;
    scantablist.SelectedTab := i;


    tabcounter := 3;


    //scantablist.Color := clBtnFace;
    scantablist.Brush.Color := panel5.color;



    foundlist3.Height := btnMemoryView.top - foundlist3.top - foundlistheightdiff;

    scantype.Top:=scantype.top+scantablist.Height+4;
  end
  else
  begin
    i := scantablist.addtab(rsScan + ' ' + IntToStr(tabcounter));
    getmem(newstate, sizeof(TScanState));
    SetupInitialScanTabState(newstate, False);
    scantablist.TabData[i] := newstate;

    scantablist.SelectedTab := i;
    Inc(tabcounter);
  end;

  if btnNextScan.Enabled then
    btnNewScan.click;

end;

procedure TMainForm.miCloseTabClick(Sender: TObject);
var
  oldscanstate: PScanState;
  oldindex: integer;
begin
  if (scantablist <> nil) and (scantablist.Count > 1) then
  begin
    //since rightclicking a tab selects it, delete the currently selected tab
    oldindex := scantablist.SelectedTab;
    oldscanstate := scantablist.TabData[scantablist.SelectedTab];

    //switch the currently selected tab to the right one if possible, else the lef tone
    if oldindex < scantablist.Count - 1 then
      scantablist.SelectedTab := oldindex + 1
    else
      scantablist.SelectedTab := oldindex - 1;

    scantablist.RemoveTab(oldindex);

    //now we can delete the tabdata
    freeandnil(oldscanstate^.foundlist);
    freeandnil(oldscanstate^.memscan);
    freememandnil(oldscanstate);
  end;
end;

procedure TMainForm.UpdateFloatRelatedPositions;
begin
  if pnlFloat.visible then
  begin
 //   cbFloatSimple.Top:=pnlFloat.Top+pnlFloat.Height;
   // cbUnrandomizer.top:=cbFloatSimple.Top+cbFloatSimple.Height;
    cbFloatSimple.visible:=true;
  end
  else
  begin
 //   cbFloatSimple.top:=pnlFloat.top;
   // cbUnrandomizer.top:=gbScanOptions.top;

    cbFloatSimple.visible:=(getVarType in [vtSingle, vtDouble, vtAll]) and (GetScanType<>soUnknownValue);
  end;

//  if cbpercentage<>nil then
//    cbFloatSimple.Top:=cbpercentage.top+cbpercentage.Height;

end;

procedure TMainForm.miFreezeNegativeClick(Sender: TObject);
begin
  addresslist.ActivateSelected(ftAllowDecrease);
end;

procedure TMainForm.miFreezePositiveClick(Sender: TObject);
begin
  addresslist.ActivateSelected(ftAllowIncrease);
end;

procedure TMainForm.miSaveScanresultsClick(Sender: TObject);
var
  n: string;
begin
  if memscan.nextscanCount > 0 then
  begin
    n := rsScanresult + ' ' + IntToStr(memscan.nextscanCount + 1);
    if inputquery(rsSaveScanResults, rsWhatNameDoYouWantToGiveToTheseScanresults, n) then
    begin
      memscan.saveresults(n);
      cbCompareToSavedScan.caption:=rsCompareToSavedScan;
      reloadPreviousResults;
    end;
  end;
end;

procedure TMainForm.miShowAsBinaryClick(Sender: TObject);
begin
  if (addresslist.selectedrecord <> nil) and
    (addresslist.selectedrecord.vartype = vtbinary) then
    addresslist.selectedrecord.extra.bitData.showasbinary := not
      addresslist.selectedrecord.extra.bitData.showasbinary;
end;

procedure TMainForm.miUndoValueClick(Sender: TObject);
begin
  if (addresslist.selectedrecord <> nil) and (addresslist.selectedrecord.canUndo) then
    addresslist.selectedrecord.UndoSetValue;
end;

procedure TMainForm.miWireframeClick(Sender: TObject);
begin
  {$ifdef windows}
  safed3dhook;
  if d3dhook<>nil then
    d3dhook.setWireframeMode(miWireframe.Checked);

  updated3dgui;
  {$endif}
end;

procedure TMainForm.miZbufferClick(Sender: TObject);
begin
  {$ifdef windows}
  safed3dhook;
  if d3dhook<>nil then
    d3dhook.setDisabledZBuffer(miZbuffer.Checked);

  updated3dgui;
  {$endif}
end;

procedure TMainForm.miZeroTerminateClick(Sender: TObject);
begin
  if (addresslist.selectedRecord <> nil) and
    (addresslist.selectedRecord.VarType = vtString) then
    addresslist.selectedRecord.Extra.stringData.ZeroTerminate := not
      addresslist.selectedRecord.Extra.stringData.ZeroTerminate;
end;

procedure TMainForm.Panel5Resize(Sender: TObject);
var
  widthleft,w,aw: integer;
  i: integer;

  f: double;
begin
 // scanvalue2.width:=(((panel5.width-5)-scanvalue.left+((andlabel.width+10) div 2)) div 2);
  if sender<>nil then
  begin
    w:=(panel5.clientwidth-scanvalue.left)-5 ;
    aw:=andlabel.width+8;
    scanvalue2.width:=(w div 2) - (aw div 2);
  end;

  //resize the foundlist columns. Do NOT do this in the onresize of the foundlist
  widthleft:=foundlist3.clientwidth-foundlist3.Columns[0].Width;

  if miShowPreviousValue.checked then
  begin
    if miOnlyShowCurrentCompareToColumn.checked then
    begin
      //old method
      w:=widthleft div 2;
      foundlist3.columns[1].width:=ceil(w*1.1);
      for i:=2 to foundlist3.columns.count-1 do
      begin
        if foundlist3.columns[i].visible then
          foundlist3.columns[i].width:=trunc(w*0.9);
      end;
    end
    else
    begin

      if (widthleft>0) and (foundlist3.ColumnCount>1) then
        w:=widthleft div (foundlist3.ColumnCount-1)
      else
        w:=4;

      //column 1 will get a %10 longer size than the compare against columns
      f:=w*1.1;
      foundlist3.columns[1].width:=ceil(f);

      widthleft:=widthleft-foundlist3.columns[1].width;
      if (widthleft>0) and (foundlist3.ColumnCount>2) then
        w:=widthleft div (foundlist3.ColumnCount-2)
      else
        w:=4;

      for i:=2 to foundlist3.ColumnCount-1 do
        foundlist3.columns[i].width:=TWidth(w);
    end;
  end
  else
  begin
    foundlist3.columns[1].width:=widthleft;
  end;

end;

procedure TMainForm.pmTablistPopup(Sender: TObject);
var
  x, y: integer;
begin
  if scantablist <> nil then //should always be true
  begin
    x := scantablist.ScreenToClient(mouse.cursorpos).x;
    y := scantablist.ScreenToClient(mouse.cursorpos).y;
    miCloseTab.Visible := scantablist.GetTabIndexAt(x, y) <> -1;
    miTablistSeperator.Visible := miCloseTab.Visible;
    miRenameTab.Visible := miCloseTab.Visible;
  end;
end;

procedure TMainForm.pmValueTypePopup(Sender: TObject);
begin
  miEditCustomType.Visible := (vartype.ItemIndex <> -1) and
    (vartype.items.objects[vartype.ItemIndex] <> nil);
  miDeleteCustomType.Visible := miEditCustomType.Visible;

  miShowCustomTypeDebug.visible:=miEditCustomType.Visible and (GetKeyState(VK_SHIFT) and 32768=32768);

end;


procedure TMainForm.miShowCustomTypeDebugClick(Sender: TObject);
var ct: TCustomType;
begin
  ct:=TCustomType(vartype.items.objects[vartype.ItemIndex]);
  ct.showDebugInfo;
end;

procedure TMainForm.miShowPreviousValueClick(Sender: TObject);
var
  reg: Tregistry;
  i: integer;
begin
  //Show/Hide the previousValue column
  //

  if miShowPreviousValue.checked then
  begin
    miOnlyShowCurrentCompareToColumn.enabled:=true;
    if miOnlyShowCurrentCompareToColumn.checked then
    begin
      foundlist3.Column[2].visible:=true;
      for i:=3 to foundlist3.columncount-1 do
        foundlist3.column[i].Visible:=false;
    end
    else
    begin
      for i:=2 to foundlist3.columncount-1 do
        foundlist3.column[i].Visible:=true;
    end;
  end
  else
  begin
    miOnlyShowCurrentCompareToColumn.checked:=false;
    miOnlyShowCurrentCompareToColumn.enabled:=false;
    for i:=2 to foundlist3.columncount-1 do
      foundlist3.column[i].Visible:=false;
  end;


  Panel5Resize(nil);

  cereg.writeBool('Show previous value column', miShowPreviousValue.checked);
end;



procedure TMainForm.doNewScan;
var c: TListColumn ;
begin
  if SaveFirstScanThread <> nil then //stop saving the results of the fist scan
  begin
    SaveFirstScanThread.Terminate;
    SaveFirstScanThread.WaitFor;
    FreeAndNil(SaveFirstScanThread);
  end;

  cleanupPreviousResults;
  //create a dummy previous column
  c:=foundlist3.Columns.Add;
  c.caption:=rsPrevious;
  c.tag:=foundlistColors.CompareToHeaderColor;
  fActivePreviousResultColumn:=2;


  fastscan := formsettings.cbFastscan.Checked;
  //close files in case of a bug i might have missed...

  vartype.Visible := True;

  foundcount := 0;
  foundlist.Clear;

  btnNewScan.Caption := strFirstScan;

  btnNextScan.Enabled := False;
  vartype.Enabled := True;

  scanvalue.Visible := True;
  scantext.Visible := True;

  Updatescantype;
  Scantype.ItemIndex := 0;

  //enable the memory scan groupbox
  setGbScanOptionsEnabled(True);

  VartypeChange(vartype);

  if scanvalue.Visible and scanvalue.Enabled then
  begin
    scanvalue.SetFocus;
    scanvalue.SelectAll;
  end;

  compareToSavedScan := False;
  lblcompareToSavedScan.Visible := False;
  cbCompareToSavedScan.Checked:=false;
  cbCompareToSavedScan.Caption:=strCompareToFirstScan;
  cbCompareToSavedScan.Visible:=false;

  miDisplayDefault.checked:=true;
  foundlistDisplayOverride:=0;

  {$ifdef windows}
  if formsettings.cbPauseWhenScanningOnByDefault.checked then
    cbPauseWhileScanning.Checked:=true;
  {$endif}

  cbpercentage.checked:=false;
end;

procedure TMainForm.btnNewScanClick(Sender: TObject);
begin
  btnFirst.click; //now completely replaced
end;

procedure TMainForm.btnNextScanClick(Sender: TObject);
begin
  btnNext.click;
end;

procedure TMainForm.btnMemoryViewClick(Sender: TObject);
begin
  memorybrowser.Show;
  if memorybrowser.WindowState=wsMinimized then
    memorybrowser.WindowState:=wsNormal;
end;



function TMainForm.onhelp(Command: word; Data: PtrInt; var CallHelp: boolean): boolean;
var
  wikipath: string;
  wikiurl: string;
begin
  callhelp := False;
  Result := True;

  wikipath:='https://wiki.cheatengine.org/index.php';
  wikiurl:='';

  if command = HELP_CONTEXT then
  begin
    case data of
      1:    wikiurl:='?';
      2:    wikiurl:='?title=Help_File:AboutLong';
      4:    wikiurl:='?title=Tutorials:AttachToProcess';
      11:   wikiurl:='?title=Help_File:Table_Extras';
      12:   wikiurl:='?title=Help_File:Memory_view';
      19:   wikiurl:='?title=Cheat_Engine:Lua';
      1089: wikiurl:='?title=Cheat_Engine:Auto_Assembler';
    end;

    {$ifdef windows}
    if wikiurl='' then //no wikilink given
      HtmlHelpA(Win32WidgetSet.AppHandle, PChar(cheatenginedir + 'cheatengine.chm'), HH_HELP_CONTEXT, Data)
    else
    {$endif}
      ShellExecute(0,'open',pchar(wikipath+wikiurl),nil,nil,SW_SHOW);

  end;

end;


procedure TMainForm.FormCreate(Sender: TObject);
var
  tokenhandle: thandle;
  {$ifdef windows}
  tp: TTokenPrivileges;
  prev: TTokenPrivileges;
  {$endif}

  ReturnLength: Dword;

  differentWidth: integer;
  x: array of integer;

  errormode: dword;
  minworkingsize, maxworkingsize: ptruint;
  //reg: tregistry;

  PODirectory, Lang, FallbackLang: string;

  rs: TResourceStream;

  i: integer;

  dir: string;
  createlog: boolean;
  s: string;
begin
  exceptionerrorcs:=TCriticalSection.Create;
  mtid:=MainThreadID;

  tthread.NameThreadForDebugging('Main GUI Thread', GetCurrentThreadId);

  PreviousResultList:=Tlist.Create;



  {$if (LCL_FULLVERSION > 1060400) and (lcl_fullversion <=1080200)}
  Foundlist3.Dragmode:=dmManual; //perhaps this gets fixed in later lcl versions, but for now, it sucks
  {$endif}

//Self.AutoAdjustLayout(lapAutoAdjustForDPI, Self.DesignTimeDPI, Screen.PixelsPerInch, Self.Width, ScaleX(Self.Width, Self.DesignTimeDPI));
//  Self.AutoAdjustLayout(lapAutoAdjustForDPI, Self.DesignTimeDPI, 200, Self.Width, ScaleX(Self.Width, Self.DesignTimeDPI));
  { font.size:=20;
  i:=FromAddress.Font.Size;
  FromAddress.Font.Size:=font.size;
  if i=0 then beep;  }

  lastAdded.vartype:=vtDword;

  miSignTable.visible:={$ifdef windows}canSignTables{$else}false{$endif};


  vartype.Items.Clear;
  vartype.items.add(rs_vtBinary);
  vartype.items.add(rs_vtByte);
  vartype.items.add(rs_vtWord);
  vartype.items.add(rs_vtDword);
  vartype.items.add(rs_vtQword);
  vartype.items.add(rs_vtSingle);
  vartype.items.add(rs_vtDouble);
  vartype.items.add(rs_vtString);
  vartype.items.add(rs_vtByteArray);
  vartype.items.add(rs_vtAll);
  vartype.items.add(rs_vtGrouped);


  {$ifdef windows}
  {$ifdef cpu64}
  //lazarus bug bypass
  if WindowsVersion = wvVista then
    foundlist3.OnCustomDrawItem := nil;
  {$endif}
  {$endif}

  {$if defined(CPU386) or defined(CPUX86_64)}
  Set8087CW($133f);
  SetSSECSR($1f80);
  {$endif}

  //FormDropFiles fix for win7, win8 and later (window message filter update)
  {$ifdef windows}
  if (WindowsVersion>=wv7) and assigned(ChangeWindowMessageFilter) then
  try
   //WM_COPYGLOBALDATA = 73; MSGFLT_ADD = 1
   ChangeWindowMessageFilter(73, 1);
   ChangeWindowMessageFilter(WM_DROPFILES, 1);
  except;
  end;
  {$endif}

  LuaFiles := TLuaFileList.Create;
  LuaForms := TList.Create;
  try
    LUA_DoScript('package.path = package.path .. [[;' + tablesdir + '\?.lua]]');
  except
    OutputDebugString('LUA_DoScript failure: package.path');
  end;

  InternalLuaFiles := TLuaFileList.Create;

  rs := TResourceStream.Create(HInstance, 'BUILDIN_ACTIVATE', RT_RCDATA);
  InternalLuaFiles.Add(TLuaFile.Create('Activate', rs));
  freeandnil(rs);


  rs := TResourceStream.Create(HInstance, 'BUILDIN_DEACTIVATE', RT_RCDATA);
  InternalLuaFiles.Add(TLuaFile.Create('Deactivate', rs));
  freeandnil(rs);


  dir:=cereg.readString('Initial tables dir');
  if dir='' then dir:=tablesdir;

  SaveDialog1.InitialDir:=dir;
  OpenDialog1.InitialDir:=dir;





//  if FileExists();
  s:=ChangeFileExt(application.exename,'.DBG');
  if FileExists(s) then
  begin
    createlog:=true;
    cedebugsymbolspresent:=true;
  end
  else
    createlog:=false;

  miEnableLCLDebug.Checked:=createlog;

  if miEnableLCLDebug.Checked then
    EnableLCLClick(miEnableLCLDebug);


  application.OnHelp := @onhelp;



  Forms.Application.ShowButtonGlyphs := sbgNever;
  application.OnException := @exceptionhandler;
  {$ifdef windows}
  errormode := SetErrorMode(0);
  setErrorMode(errormode or SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
  {$endif}


  frmLuaTableScript := TfrmAutoInject.Create(self);
  frmLuaTableScript.ScriptMode := smLua;

  frmLuaTableScript.Caption := rsLuaScriptCheatTable;
  frmLuaTableScript.Save1.OnClick := miSave.onclick;
  frmLuaTableScript.SaveAs1.OnClick:= save1.OnClick;
  frmLuaTableScript.Name := 'frmLuaTableScript';


  hotkeypressed := -1;



  tokenhandle := 0;
  {$ifdef windows}
  if ownprocesshandle <> 0 then
  begin
    if OpenProcessToken(ownprocesshandle, TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES,
      tokenhandle) then
    begin
      ZeroMemory(@tp, sizeof(tp));

      if lookupPrivilegeValue(nil, 'SeDebugPrivilege', tp.Privileges[0].Luid) then
      begin
        tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        tp.PrivilegeCount := 1; // One privilege to set
        if not AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp),
          prev, returnlength) then
          ShowMessage(rsFailureSettingTheDebugPrivilege);
      end;

      if lookupPrivilegeValue(nil, 'SeTcbPrivilege', tp.Privileges[0].Luid) then
      begin
        tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        tp.PrivilegeCount := 1; // One privilege to set
        if not AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp),
          prev, returnlength) then
          ShowMessage(rsFailureSettingTheSeTcbPrivilegePrivilege);
      end;

      if lookupPrivilegeValue(nil, 'SeTcbPrivilege', tp.Privileges[0].Luid) then
      begin
        tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        tp.PrivilegeCount := 1; // One privilege to set
        if not AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp),
          prev, returnlength) then
          ShowMessage(rsFailureSettingTheSeTcbPrivilegePrivilege);
      end;


      ZeroMemory(@tp, sizeof(tp));
      if lookupPrivilegeValue(nil, SE_LOAD_DRIVER_NAME, tp.Privileges[0].Luid) then
      begin
        tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        tp.PrivilegeCount := 1; // One privilege to set
        if not AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp),
          prev, returnlength) then
          ShowMessage(rsFailureSettingTheLoadDriverPrivilege);
      end;




      if GetSystemType >= 7 then
      begin
        ZeroMemory(@tp, sizeof(tp));
        if lookupPrivilegeValue(nil, 'SeCreateGlobalPrivilege',
          tp.Privileges[0].Luid) then
        begin
          tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
          tp.PrivilegeCount := 1; // One privilege to set
          if not AdjustTokenPrivileges(tokenhandle, False, tp,
            sizeof(tp), prev, returnlength) then
            ShowMessage(rsFailureSettingTheCreateGlobalPrivilege);
        end;



        {$ifdef cpu64}
        ZeroMemory(@tp, sizeof(tp));
        ZeroMemory(@prev, sizeof(prev));

        if lookupPrivilegeValue(nil, SE_LOCK_MEMORY_NAME, tp.Privileges[0].Luid) then
        begin
          tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
          tp.PrivilegeCount := 1; // One privilege to set
          AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);

        end;

        {$endif}
      end;


      ZeroMemory(@tp, sizeof(tp));
      ZeroMemory(@prev, sizeof(prev));
      if lookupPrivilegeValue(nil, 'SeIncreaseWorkingSetPrivilege',
        tp.Privileges[0].Luid) then
      begin
        tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        tp.PrivilegeCount := 1; // One privilege to set
        AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
      end;

    end;

    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeSecurityPrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;


    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeTakeOwnershipPrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;

    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeManageVolumePrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;

    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeBackupPrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;

    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeCreatePagefilePrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;

    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeShutdownPrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;

    ZeroMemory(@tp, sizeof(tp));
    ZeroMemory(@prev, sizeof(prev));
    if lookupPrivilegeValue(nil, 'SeRestorePrivilege', tp.Privileges[0].Luid) then
    begin
      tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tp.PrivilegeCount := 1; // One privilege to set
      AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp), prev, returnlength);
    end;


    if GetProcessWorkingSetSize(ownprocesshandle, minworkingsize, maxworkingsize) then
      SetProcessWorkingSetSize(ownprocesshandle, 16 * 1024 * 1024, 64 * 1024 * 1024);

  end;

  {$endif}


  tempbitmap := TBitmap.Create;

  scanvalue.Text := '';

(* removed because it uses symhandler now
  {$ifdef cpu64}
  fromaddress.MaxLength := 16;
  toaddress.MaxLength := 16;
  {$else}
  fromaddress.MaxLength := 8;
  toaddress.MaxLength := 8;
  {$endif}
*)

  miResetRange.click;

  isbit := False;
  {$if defined(CPU386) or defined(CPUX86_64)}
  old8087CW := Get8087CW;
  Set8087CW($133f);
  SetSSECSR($1f80);
  {$endif}



  debugproc := False;

  //get current screen resolution (when switching back for debug)
  originalwidth := screen.Width;
  originalheight := screen.Height;

  Memimage := TMemorystream.Create;

  oldwidth := screen.Width;
  oldheight := screen.Height;

  ProcessHandler.ProcessHandle := 0;

  logo.Hint := strClickToGoHome;

  logo.ShowHint := True;

  newaddress := 0;

  VarType.ItemIndex := 3;
  oldvartype := 3;

  UpdateScantype;
  ScanType.ItemIndex := 0;

  btnNewScan.Caption := strFirstScan;
  hookedin := False;

  //allignment fixes for some window style's that mess up with thick borders (like vista)
  differentWidth := logopanel.left - (clientwidth - logopanel.Width);
  btnAddAddressManually.Left := clientwidth - btnAddAddressManually.Width;
  commentbutton.left := clientwidth - commentbutton.Width;
  logopanel.left := clientwidth - logopanel.Width;
  ProgressBar.Width := ProgressBar.Width - differentwidth;
  undoscan.left := undoscan.left - differentwidth;

  //create object for the auto attach list
  autoattachlist := TStringList.Create;
  autoattachlist.CaseSensitive := False; //set it up as not case sensitive
  autoattachlist.Delimiter := ';';

  extraautoattachlist := TStringList.Create;
  extraautoattachlist.CaseSensitive := False; //set it up as not case sensitive
  extraautoattachlist.Delimiter := ';';
  extraautoattachlist.Duplicates := dupIgnore;

  randomize;



{$ifdef ceasinjectabledll}
  //panel7.Visible:=false;
  sbOpenProcess.Enabled := False;
  processid := getcurrentprocessid;
  processhandle := getcurrentprocess;
  enableGui;
  processlabel.Caption := Inttohex(processid, 8) + ' : ' + rsCurrentProcess;
{$endif}



  oldhandle := mainform.handle;

  addresslist := TAddresslist.Create(self);
  addresslist.Width := 500;
  addresslist.Height := 150;
  addresslist.top := 50;
  addresslist.parent := panel1;
  addresslist.PopupMenu := popupmenu2;
  addresslist.OnDropByListview := @AddresslistDropByListview;
  addresslist.OnAutoAssemblerEdit := @AddressListAutoAssemblerEdit;
  addresslist.Align := alClient;
  addresslist.AutoSize:=true;


  symhandler.loadCommonModuleList;

  setlength(x, 7);
  if loadformposition(self, x) then
  begin
    autosize:=false;
    addresslist.headers.Sections[0].Width := x[0];
    addresslist.headers.Sections[1].Width := x[1];
    addresslist.headers.Sections[2].Width := x[2];
    addresslist.headers.Sections[3].Width := x[3];
    addresslist.headers.Sections[4].Width := x[4];
    panel5.Height := x[5];
    foundlist3.columns[0].Width := x[6];
  end;

  mainform:=self;



  pluginhandler := TPluginhandler.Create;

  //custom types
  LoadCustomTypesFromRegistry;


  {$ifdef windows}
  XInputMessages(true);
  {$endif}

  luaclass_newClass(luavm, self);
  lua_setglobal(luavm,'MainForm');

  luaclass_newClass(luavm, addresslist);
  lua_setglobal(luavm,'AddressList');

  miEnableLCLDebug.checked:=createlog;
  allocsAddToUnexpectedExceptionList:=cereg.readBool('Add Allocated Memory As Watched');
  case cereg.readInteger('Unexpected Breakpoint Behaviour',0) of
    0: UnexpectedExceptionAction:=ueaIgnore;
    1: UnexpectedExceptionAction:=ueaBreak;
    2: UnexpectedExceptionAction:=ueaBreakIfInRegion;
  end;


  RecentFiles:=tstringlist.Create;
  cereg.readStrings('Recent Files', RecentFiles);


  cbSpeedhack.caption:=rsEnableSpeedHack;


  {$ifdef darwin}
  cbDirty:=TCheckBox.create(self);
  cbDirty.parent:=panel2;
  cbDirty.AllowGrayed:=true;

  cbDirty.AnchorSideTop.Control:=cbCopyOnWrite;
  cbDirty.AnchorSideTop.Side:=asrTop;

  cbDirty.AnchorSideLeft.Control:=cbExecutable;
  cbDirty.AnchorSideLeft.Side:=asrLeft;
  cbDirty.Caption:=rsModified;
  cbDirty.State:=cbGrayed;

  mi3d.Visible:=false;

  cut1.ShortCut:=TextToShortCut('Meta+X');
  copy1.ShortCut:=TextToShortCut('Meta+C');
  paste1.ShortCut:=TextToShortCut('Meta+V');
  menuitem1.ShortCut:=TextToShortCut('Meta+A');

  miTutorial.Visible:=false;
  menuitem15.Visible:=false;


  if MacIsArm64 then
    MenuItem16.visible:=true;

  cbPresentMemoryOnly.Visible:=false;
  sbClearActiveMemory.visible:=false;

  {$endif}
end;

procedure TMainForm.ChangedHandle(Sender: TObject);
begin
 // memscan.setScanDoneCallback(mainform.handle, wm_scandone);

  //reset the hotkeys
  hotkeyTargetWindowHandleChanged(oldhandle, mainform.handle);
  oldhandle := mainform.handle;
end;

procedure TMainForm.AddressKeyPress(Sender: TObject; var Key: char);
begin
  hexadecimal(key);
end;

procedure TMainForm.FoundListDblClick(Sender: TObject);
var i: integer;
begin
  if foundList3.SelCount > 0 then
  begin
    if FoundList3.itemindex<>-1 then
      AddToRecord(FoundList3.ItemIndex)
    else
    begin
      if foundlist3.selected<>nil then
        AddToRecord(FoundList3.selected.Index)
      else
      begin
        if foundList3.Items.Count<100 then
        begin
          for i:=0 to foundList3.items.count-1 do
            if foundlist3.Items[i].Selected then
              AddToRecord(i);
        end
        else
          if foundList3.Items.Count>0 then
            AddToRecord(0);
      end;
    end;

  end;
end;

procedure TMainForm.Browsethismemoryarrea1Click(Sender: TObject);
var
  b: dword;
  s: string;
begin
  if (foundlist3.ItemIndex <> -1) then
  begin
    MemoryBrowser.memoryaddress := foundlist.GetAddress(foundlist3.ItemIndex, b, s);
    memorybrowser.Show;
  end;
end;

procedure TMainForm.tLuaGCActiveTimer(Sender: TObject);
begin
  if (lua_gc(LuaVM,LUA_GCCOUNT,0)<luagc_MinSize) then exit;

  lua_gc(LuaVM, LUA_GCCOLLECT,0);
  lua_gc(LuaVM, LUA_GCCOLLECT,0);
end;

procedure TMainForm.tLuaGCPassiveTimer(Sender: TObject);
begin
  lua_gc(LuaVM,LUA_GCSTEP,500);
end;

procedure TMainForm.UpdateTimerTimer(Sender: TObject);
begin
  try
    if addresslist <> nil then
      addresslist.Refresh;

    Inc(reinterpretcheck);
    if reinterpretcheck mod 15 = 0 then
      reinterpretaddresses;
  except
    on e: exception do
    begin
      UpdateTimer.Enabled:=false;

      MessageDlg('UpdateTimer Error:'+e.Message, mtError, [mbok],0);
    end;
  end;
end;

procedure TMainForm.FreezeTimerTimer(Sender: TObject);
var i: integer;
begin
  try
    if addresslist <> nil then
      addresslist.ApplyFreeze;
  except
    on e:exception do
    begin
      OutputDebugString('FreezeTimerTimer:'+e.Message);
    end;
  end;
end;




//vars for changevalue
var
  differentsizesanswer: boolean;
  terminatewith0answer: boolean;
  askfordifferentsizesonce: boolean;
  asked: boolean;




procedure TMainForm.Browsethismemoryregion1Click(Sender: TObject);
begin
  if addresslist.selectedrecord <> nil then
  begin
    memorybrowser.hexview.address := addresslist.selectedrecord.GetRealAddress;
    memorybrowser.Show;
  end;
end;

procedure TMainForm.Deletethisrecord1Click(Sender: TObject);
begin
  addresslist.DeleteSelected;
end;

procedure TMainForm.ScanvalueoldKeyPress(Sender: TObject; var Key: char);
begin
  checkpaste;

  if key = chr(13) then
  begin
    if btnNextScan.Enabled then
      btnNextScan.Click
    else
      btnNewScan.Click;

    key := #0;
    exit;
  end;
end;



procedure TMainForm.Calculatenewvaluepart21Click(Sender: TObject);
var
  _newaddress: ptrUint;
  calculate: int64;
  i, j, err: integer;
  selectedi: integer;

  firstispointer: boolean;
  re: string;
  ok: boolean;

  res: integer;

  sel: TMemoryRecord;
  tempaddress: ptrUint;

  updatelist: Tlist;
  tn: TTreenode;
  minlevel: integer; //if the scan for entries goes below this, it means it got outside the current node

begin
  if (addresslist.Count = 0) or (addresslist.SelCount=0) then
    exit;


  res := -1;

  //first find out how many where selected.
  i := 0;
  selectedi := addresslist.SelCount;

  firstispointer := False;

  sel := addresslist.selectedRecord;
  if sel = nil then
    sel := addresslist[0];


  if sel.IsPointer then
    if messagedlg(strSelectedAddressIsAPointer, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
      exit
    else
      firstispointer := True;


  if selectedi > 1 then
  begin
    //see if there are (other) pointers selected
    for i := 0 to addresslist.Count - 1 do
      if (addresslist[i] <> sel) and (addresslist[i].isselected) and
        (addresslist[i].IsPointer) then
      begin
        if firstispointer then
          re := strMorePointers
        else
          re := strMorePointers2;

        break;
      end;
  end
  else
  begin
    //all addresses
    for i := 0 to addresslist.Count - 1 do
      if (addresslist[i] <> sel) and (addresslist[i].IsPointer) then
      begin
        if firstispointer then
          re := strMorePointers
        else
          re := strMorePointers2;

        break;
      end;
  end;



  _newaddress := sel.GetRealAddress;
  if (foundlist3.SelCount > 0) then
    _newaddress := foundlist.GetAddress(foundlist3.ItemIndex);


  changeoffset := TChangeOffset.Create(self);

  changeoffset.FromAddress := sel.getBaseAddress;

  changeoffset.toAddress := _newaddress;
  if changeoffset.showmodal = mrCancel then
    exit;

  if changeoffset.error > 0 then
    raise Exception.Create(strNotAValidValue);
  calculate := changeoffset.offset;



  updatelist:=TList.create;
  if (addresslist.SelCount=1) then //recalculate all siblings and their children
  begin
    tn:=addresslist.selectedRecord.treenode.parent;
    if tn=nil then //everything
    begin
      for i:=0 to addresslist.count-1 do
        updatelist.Add(addresslist[i]);
    end
    else
    begin
      //only the siblings and children

      tn:=tn.Items[0];
      minlevel:=tn.level;

      while (tn<>nil) and (tn.level>=minlevel) do
      begin
        updatelist.add(tn.data);
        tn:=tn.GetNext;
      end;

    end;
  end
  else
  begin
    //recalculate all the selected entries
    for i:=0 to addresslist.count-1 do
      if addresslist[i].isSelected then
        updatelist.add(addresslist[i]);
  end;

  //now recalculate all the selected entries
  for i:=0 to updatelist.count-1 do
  begin
    if not tmemoryrecord(updatelist[i]).isOffset then
    begin
      tempaddress := tmemoryrecord(updatelist[i]).getBaseAddress;
      Inc(tempaddress, calculate);
      tmemoryrecord(updatelist[i]).interpretableaddress := symhandler.getNameFromAddress(tempaddress, True, True, False);
    end;
  end;

  freeandnil(updatelist);
  addresslist.ReinterpretAddresses;
end;

procedure TMainForm.btnAddAddressManuallyClick(Sender: TObject);
var mr: Tmemoryrecord;
begin
  mr:=addresslist.addAddressManually(lastAdded.Address, lastAdded.vartype, lastAdded.CustomTypeName);
  if mr<>nil then
  begin
    lastAdded.Address:=mr.interpretableaddress; //store the last used string
    lastAdded.vartype:=mr.VarType;
    lastAdded.CustomTypeName:=mr.CustomTypeName;
  end;
end;

procedure TMainForm.ScanTypeChange(Sender: TObject);
begin
  updatescantype;
end;

procedure TMainForm.Value1Click(Sender: TObject);
begin
  addresslist.doValueChange;
end;

function TMainForm.convertvalue(ovartype, nvartype: integer; oldvalue: string;
  washexadecimal, ishexadecimal: boolean): string;
var
  s: string;
  oldvaluei: qword;
  oldvaluef: double absolute oldvaluei;
  oldvalueba: pbyte;

  newvaluei: qword;
  newvaluef: double absolute newvaluei;
  newvalueba: pbyte;

  i: integer;

  ba: TBytes;

  wasfloat: boolean;
  wasaob: boolean;

  hasbytes: boolean;
  puretext: boolean;
begin
  if ovartype = nvartype then
  begin
    Result := oldvalue;
    exit;
  end;

  Result := '';
  oldvalueba := @oldvaluei;
  newvalueba := @newvaluei;

  try
    puretext := False;
    wasfloat := False;
    wasaob := False;
    oldvaluei := 0;

    try
      case ovartype of
        0:
        begin
          //binary
          if rbdec.Checked then
            oldvaluei := StrToQWordEx(scanvalue.Text)
          else
          begin
            s := trim(oldvalue);
            for i := 1 to length(s) do
              if not (s[i] in ['0', '1']) then
                s[i] := '0';

            oldvaluei := parsers.BinToInt(s);
          end;
        end;

        1..4:
        begin
          if washexadecimal then
          begin
            oldvaluei := StrToQWordEx('$' + oldvalue);
          end
          else
            oldvaluei := StrToQWordEx(oldvalue);
        end;

        5, 6, 9:
        begin
          try
            oldvaluei := StrToInt(oldvalue);
          except
            oldvaluef := strtofloat(oldvalue);
            wasfloat := True;
          end;
        end;

        7: //generic type,  text or all
        begin
          try
            oldvaluei := StrToQWordEx(oldvalue);
          except
            oldvaluef := StrToFloat(oldvalue);
            wasfloat := True;
          end;

        end;

        8:
        begin //convert the aob to an integer if possible (max 8 bytes)
          //aob
          setlength(ba, 0);
          ConvertStringToBytes(oldvalue, washexadecimal, ba);

          oldvaluei := 0;
          for i := 0 to min(7, length(ba) - 1) do
          begin
            if ba[i] < 0 then
              ba[i] := 0;

            oldvalueba[i] := ba[i];
          end;

          wasaob := True;
        end;

        else
        begin
          if ovartype>=11 then
          begin
            if washexadecimal then
            begin
              oldvaluei := StrToQWordEx('$' + oldvalue);
            end
            else
              oldvaluei := StrToQWordEx(oldvalue);
          end;
        end;
      end;
    except
      //could not get parsed, if the target is aob then convert the text to an aob, else give up
      if nvartype = 8 then
        puretext := True
      else
      begin
        Result := '';
        exit;
      end;
    end;


    case nvartype of
      0: //binary
      begin
        if wasfloat then
          oldvaluei := trunc(oldvaluef); //convert the float to an integer

        if rbdec.Checked then
          Result := IntToStr(oldvaluei)
        else
          Result := parsers.IntToBin(oldvaluei);

      end;

      1..4: //integer or custom
      begin
        if wasfloat then
          oldvaluei := trunc(oldvaluef); //convert the float to an integer

        if ishexadecimal then
          Result := inttohex(oldvaluei, 1)
        else
          Result := IntToStr(oldvaluei);
      end;

      5..6, 9: //float
      begin
        if wasfloat then
          Result := oldvalue
        else
        begin
          if wasaob then
          begin
            try
              Result := floattostr(oldvaluef);
            except

            end;
          end
          else
            Result := IntToStr(oldvaluei);
        end;
      end;

      7:
      begin
        //text
        if wasaob then
        begin
          //convert the aob to text
          s := '';
          //ba should still be intact:
          for i := 0 to length(ba) - 1 do
          begin
            if ba[i] < 0 then
              ba[i] := 0;

            if ba[i] >= 32 then
              s := s + chr(ba[i])
            else
              s := s + '.';

            Result := s;
          end;
        end
        else
          Result := oldvalue;
      end;



      8:
      begin
        s := '';

        if (puretext) then
        begin
          for i := 1 to length(oldvalue) do
          begin
            if ishexadecimal then
              s := s + inttohex(pbyte(@oldvalue[i])^, 2) + ' '
            else
              s := s + IntToStr(pbyte(@oldvalue[i])^) + ' ';
          end;
        end
        else
        begin

          hasbytes := False;
          for i := 7 downto 0 do
          begin
            if hasbytes or (oldvalueba[i] <> 0) then
            begin
              hasBytes := True;
              if ishexadecimal then
                s := inttohex(oldvalueba[i], 2) + ' ' + s
              else
                s := IntToStr(oldvalueba[i]) + ' ' + s;
            end;
          end;

          trim(s);
        end;



        Result := s;
      end;

      else
      begin
        if nvartype>=11 then
        begin
          if wasfloat then
            oldvaluei := trunc(oldvaluef); //convert the float to an integer

          if ishexadecimal then
            Result := inttohex(oldvaluei, 1)
          else
            Result := IntToStr(oldvaluei);
        end;
      end;

    end;


  except
  end;

end;

procedure TMainForm.createGroupConfigButton;
begin
  if groupconfigbutton=nil then
  begin
    groupconfigbutton:=Tbutton.create(self);
    groupconfigbutton.Name:='groupconfigbutton';
    groupconfigbutton.caption:=rsMUGenerateGroupscanCommand;
    groupconfigbutton.parent:=scantype.Parent;
    groupconfigbutton.Left:=scantype.left;
    groupconfigbutton.top:=scantype.top;
    groupconfigbutton.width:=scantype.width;
    groupconfigbutton.height:=scantype.height;

    groupconfigbutton.AnchorSideTop.Side:=asrBottom;
    groupconfigbutton.AnchorSideTop.Control:=scanvalue;
    groupconfigbutton.BorderSpacing.Top:=scantype.top-(scanvalue.Top+scanvalue.Height);

    groupconfigbutton.AnchorSideLeft.Control:=VarType;
    groupconfigbutton.AnchorSideLeft.Side:=asrLeft;
    groupconfigbutton.AnchorSideRight.Control:=VarType;
    groupconfigbutton.AnchorSideRight.Side:=asrRight;


    groupconfigbutton.Anchors:=[akTop, akLeft, akRight];// scantype.anchors;


    vartype.AnchorSideTop.Control:=groupconfigbutton;
    panel9.AnchorSideTop.Control:=groupconfigbutton;


    groupconfigbutton.OnClick:=@DoGroupconfigButtonClick;

    foundlist3.BringToFront;
  end;
end;

procedure TMainForm.destroyGroupConfigButton;
begin
  if groupconfigbutton<>nil then
  begin
    vartype.AnchorSideTop.Control:=ScanType;
    panel9.AnchorSideTop.Control:=ScanType;
    freeandnil(groupconfigbutton);
  end;
end;

procedure TMainForm.VarTypeChange(Sender: TObject);
var
  a: int64;
  pa: ^int64;
  pb: ^dword;
  b: double;
  d: single;
  i: integer;
  hexvis: boolean;
  decbitvis: boolean;
  hextext: string;
  casevis: boolean;

  oldscantype: integer;
  temp: string;

  newvartype: integer;
  unicodevis: boolean;
  tc: tbitmap;

  alignsize: integer;

  //----new convertor:
  _oldvartype, _newvartype: integer;

  washex: boolean;
  oldvalue: string;

  ct: TCustomType;
begin
  //todo: rewrite this
  oldscantype := scantype.ItemIndex;
  newvartype := vartype.ItemIndex;

  _oldvartype := oldvartype;
  _newvartype := newvartype;
  washex := cbHexadecimal.Checked;
  oldvalue := scanvalue.Text;


  dontconvert := True;

  hexvis := True;
  unicodevis := False;

  hextext := rsHex;
  casevis := False;

  decbitvis := False;
  ct:=TCustomType(vartype.Items.Objects[vartype.ItemIndex]);

  if rbFsmAligned.Checked and (not alignsizechangedbyuser) then
  begin
    if ct <> nil then
    begin
      //custom type is ALWAYS the decider
      if rbFsmAligned.Checked then
        edtAlignment.Text := inttohex(ct.preferedAlignment, 1);
    end
    else
    begin
      try
        case newvartype of
          VARTYPE_INDEX_BINARY, VARTYPE_INDEX_BYTE, VARTYPE_INDEX_TEXT, VARTYPE_INDEX_AOB, VARTYPE_INDEX_ALL: alignsize := 1; //byte, aob, string
          VARTYPE_INDEX_WORD: alignsize := 2; //word
          else
            alignsize := 4; //dword, float, single, etc...
        end;

        if rbFsmAligned.Checked then
          edtAlignment.Text := inttohex(alignsize, 1);
      except
      end;
    end;

  end;




  oldvartype := vartype.ItemIndex;

  if not (oldscantype in [smallerthan, biggerthan, valueBetween,
    exact_value, Advanced_Scan]) then
    scantype.ItemIndex := 0;



  if (newvartype in [VARTYPE_INDEX_BYTE, VARTYPE_INDEX_WORD, VARTYPE_INDEX_DWORD, VARTYPE_INDEX_QWORD, VARTYPE_INDEX_ALL]) or (newvartype >= VARTYPE_INDEX_CUSTOMBASE) then //if normal or custom type
  begin
    if (ct<>nil) and (ct.scriptUsesString) then
    begin
      scantype.ItemIndex := 0;
      casevis := True;
      if _oldvartype<>VARTYPE_INDEX_TEXT then
        cbCasesensitive.Checked := True;

      cbCasesensitive.ShowHint := False;
      cbHexadecimal.Enabled := btnNewScan.Enabled;
      hexvis := False;
    end
    else
    begin
      casevis := False;
      hexvis := True;
      scanvalue.MaxLength := 0;
      cbHexadecimal.Enabled := btnNewScan.Enabled;
    end;
    //cbHexadecimal.Checked:=hexstateForIntTypes;
  end
  else

    case newvartype of
      VARTYPE_INDEX_BINARY:
      begin //binary
        rbdec.Checked := True;
        cbHexadecimal.Checked := False;
        cbHexadecimal.Visible := False;
        decbitvis := True;
        Scantype.ItemIndex := 0;
      end;

      VARTYPE_INDEX_SINGLE:
      begin //float;
        casevis := False;

        cbHexadecimal.Checked := False;
        cbHexadecimal.Enabled := False;
        scanvalue.MaxLength := 0;
      end;

      VARTYPE_INDEX_DOUBLE:
      begin //double
        hexvis := False;
        temp := scanvalue.Text;


        cbHexadecimal.Checked := False;
        cbHexadecimal.Enabled := False;
        scanvalue.MaxLength := 0;
      end;

      VARTYPE_INDEX_TEXT:
      begin //text
        scantype.ItemIndex := 0;
        casevis := True;
        if _oldvartype<>VARTYPE_INDEX_TEXT then
          cbCasesensitive.Checked := True;

        cbCasesensitive.ShowHint := False;
        unicodevis := True;

        cbHexadecimal.Enabled := btnNewScan.Enabled;
        hexvis := False;
      end;

      VARTYPE_INDEX_AOB:
      begin  //array of byte
        scantype.ItemIndex := 0;
        scanvalue.MaxLength := 0;
        cbHexadecimal.Enabled := btnNewScan.Enabled;
        cbHexadecimal.Checked := True;

      end;


    end;

  cbHexadecimal.Caption := hextext;

  //group code (12/4/2011)
  scantype.visible:=newvartype<>10;
  lblscantype.visible:=newvartype<>10;

  if newvartype=10 then
  begin
    //create groupconfig button
    createGroupConfigButton;
  end
  else
  begin
    //destroy button if it exists
    destroyGroupConfigButton;
  end;


  cbHexadecimal.Visible := hexvis;
  rbdec.Visible := decbitvis;
  rbbit.Visible := decbitvis;

  pnlScanValueOptions.visible:=(cbHexadecimal.Visible or rbDec.visible or rbBit.Visible);




  cbunicode.Visible := unicodevis;
  cbCodePage.visible:= unicodevis;

  cbCaseSensitive.Visible := casevis;

  cbfastscan.Enabled := btnNewScan.Enabled and (not btnNextScan.Enabled);
  //only enabled when btnNewScan is enabled and nextscan not



  UpdateScanType;
  dontconvert := False;

  //set the old vartype
  oldvartype := vartype.ItemIndex;

  for i := 0 to panel5.ControlCount - 1 do
  begin
    panel5.Controls[i].Refresh;
    panel5.Controls[i].Repaint;
    panel5.Controls[i].Invalidate;
  end;


  if decbitvis then
    cbHexadecimal.Visible := False;

  scanvalue.Text := convertvalue(_oldvartype, _newvartype, oldvalue,
    washex, cbhexadecimal.Checked);


  panel5.OnResize(panel5); //lazarus, force the scantext left


  if ScanType.itemindex=-1 then
    ScanType.itemindex:=0; //just in case something has set it to -1

  if pnlScanValueOptions.visible then
  begin
    if foundlist3.width>pnlScanValueOptions.left then
      foundlist3.width:=foundlist3.width-(foundlist3.width-pnlScanValueOptions.left)-2;
  end;


end;

procedure TMainForm.LogoClick(Sender: TObject);
var s: string;
begin
  s:=format('http://www.cheatengine.org/?referredby=CE%.2f',[ceversion]);
  if messagedlg(rsDoYouWantToGoToTheCheatEngineWebsite, mtConfirmation,
    [mbYes, mbNo], 0) = mrYes then
    ShellExecute(0, PChar('open'), PChar(s),
      PChar(''), PChar(''), SW_MAXIMIZE);

end;

procedure TMainForm.VarTypeDropDown(Sender: TObject);
begin
  vartype.DropDownCount := vartype.items.Count;
end;

procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
  CanClose := mustclose or CheckIfSaved;
end;



procedure TMainForm.SpeedButton2Click(Sender: TObject);
begin
  if messagedlg(strdeleteall, mtConfirmation, [mbNo, mbYes], 0) = mrYes then
    addresslist.Clear;
end;




procedure TMainForm.AddresslistDropByListview(Sender: TObject;
  node: TTreenode; attachmode: TNodeAttachMode);
var
  i: integer;
begin

  for i := 0 to foundlist3.Items.Count - 1 do
    if foundlist3.Items[i].Selected then
    begin
      try
        AddToRecord(i, node, attachmode);
      except
      end;
    end;

  if node<>nil then node.Expand(false);
end;

procedure TMainForm.SpeedButton3Click(Sender: TObject);
begin
  AddresslistDropByListview(addresslist, nil, naAdd);
end;



procedure TMainForm.Selectallitems1Click(Sender: TObject);
var
  i: integer;
begin
  foundlist3.BeginUpdate;
  try

    for i := 0 to foundlist3.Items.Count - 1 do
    begin
      //foundlist3.items[i].Selected := True;
      foundlist3.Items[i].Selected := True;
    end;
  finally
    foundlist3.EndUpdate;
  end;

end;



procedure TMainForm.Freezealladdresses2Click(Sender: TObject);
begin
  if addresslist.selectedRecord <> nil then
  begin
    if addresslist.selectedRecord.active then
      addresslist.DeactivateSelected
    else
      addresslist.ActivateSelected;
  end;
end;




procedure TMainForm.PopupMenu2Popup(Sender: TObject);

var
  i: integer;

  //6.0
  selectionCount: integer;
  selectedrecord: TMemoryRecord;

begin
  sethotkey1.Caption := rsSetChangeHotkeys;

  selectedrecord := addresslist.selectedRecord;
  selectionCount := 0;
  for i := 0 to addresslist.Count - 1 do
    if addresslist.MemRecItems[i].isSelected then
      Inc(selectioncount);


  miZeroTerminate.Visible := (selectedrecord <> nil) and (selectedrecord.VarType = vtString);
  miZeroTerminate.Checked := (miZeroTerminate.Visible) and
    (selectedrecord.Extra.stringData.ZeroTerminate);

  DeleteThisRecord1.Visible := (addresslist.selectedRecord <> nil);
  Change1.Visible := (addresslist.selectedrecord <> nil) and
    (not (addresslist.selectedRecord.vartype = vtAutoAssembler));
  address1.visible := (addresslist.selectedrecord <> nil) and (not addresslist.selectedRecord.isGroupHeader or addresslist.selectedRecord.isAddressGroupHeader);
  Type1.visible := (addresslist.selectedrecord <> nil) and (not addresslist.selectedRecord.isGroupHeader);
  Value1.visible := (addresslist.selectedrecord <> nil);
  Smarteditaddresses1.visible := (addresslist.selectedrecord <> nil) and (not addresslist.selectedRecord.isGroupHeader or addresslist.selectedRecord.isAddressGroupHeader);

  BrowseThisMemoryRegion1.Visible :=(addresslist.selectedRecord <> nil) and (not addresslist.selectedRecord.isGroupHeader or addresslist.selectedRecord.isAddressGroupHeader) and (not (addresslist.selectedRecord.vartype = vtAutoAssembler));
  miDisassemble.Visible:=Browsethismemoryregion1.Visible;

  ShowAsHexadecimal1.Visible :=
    (addresslist.selectedRecord <> nil) and (addresslist.selectedRecord.VarType in
    [vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble, vtCustom, vtByteArray]) and
    (not addresslist.selectedRecord.isGroupHeader);


  miShowAsSigned.visible:=(addresslist.selectedRecord <> nil) and (not addresslist.selectedRecord.showAsHex) and (addresslist.selectedRecord.VarType<>vtAutoAssembler) and (not addresslist.selectedRecord.isGroupHeader);
  miShowAsSigned.Checked:=(addresslist.selectedRecord <> nil) and (addresslist.selectedrecord.showAsSigned);

  if (addresslist.selectedRecord <> nil) and (addresslist.selectedrecord.VarType =
    vtBinary) then
  begin
    if addresslist.selectedRecord.Extra.bitData.showasbinary then
      miShowAsBinary.Caption := rsShowAsDecimal
    else
      miShowAsBinary.Caption := rsShowAsBinary;

    miShowAsBinary.Visible := True;
  end
  else
    miShowAsBinary.Visible := False;


  if (addresslist.selectedRecord <> nil) then
  begin
    if not addresslist.selectedRecord.showAsHex then
      ShowAsHexadecimal1.Caption := rsShowAsHexadecimal
    else
      ShowAsHexadecimal1.Caption := rsShowAsDecimal;
  end;



  SetHotkey1.Visible := (addresslist.selectedRecord <> nil);
  if SetHotkey1.visible and addresslist.selectedRecord.hasHotkeys then
    SetHotkey1.caption:=rsSetChangeHotkeys
  else
    SetHotkey1.caption:=rsSetHotkeys;


  //6.1: Groupheaders can also have hotkeys (for toggle hotkeys)

  Freezealladdresses2.Visible := (addresslist.selectedRecord <> nil);

  Changescript1.Visible := (addresslist.selectedRecord <> nil) and
    (addresslist.selectedrecord.VarType = vtAutoAssembler);

  miAsyncScript.visible:=Changescript1.Visible;
  if miAsyncScript.visible then
    miAsyncScript.Checked:=addresslist.selectedrecord.Async;

  n5.Visible := (addresslist.selectedRecord <> nil);

  Pointerscanforthisaddress1.Visible := BrowseThisMemoryRegion1.Visible;

  miGeneratePointermap.Visible:=processid<>0;

  Findoutwhataccessesthisaddress1.Visible := BrowseThisMemoryRegion1.Visible;
  Setbreakpoint1.Visible := BrowseThisMemoryRegion1.Visible;

  sep1.Visible := BrowseThisMemoryRegion1.Visible;
  Calculatenewvaluepart21.Visible := (addresslist.Count > 0);
  Forcerechecksymbols1.Visible := addresslist.Count > 0;

  //one extra check for recalculate (don't show it when an aa address is selected)
  if (addresslist.selectedRecord <> nil) and
    (addresslist.selectedRecord.vartype = vtAutoAssembler) then
    Calculatenewvaluepart21.Visible := False;

  n4.Visible := (addresslist.Count > 0) or (miGeneratePointermap.visible);

  n1.Visible := True;
  CreateGroup.Visible := True;

  if (selectedrecord <> nil) and selectedrecord.treenode.HasChildren then
  begin
    miGroupconfig.Visible := True;
    miHideChildren.Checked := moHideChildren in selectedrecord.options;
    miBindActivation.Checked := moActivateChildrenAsWell in selectedrecord.options;
    miBindDeactivation.checked := moDeactivateChildrenAsWell in selectedrecord.options;
    miRecursiveSetValue.Checked := moRecursiveSetValue in selectedrecord.options;
    miAllowCollapse.checked := moAllowManualCollapseAndExpand in selectedrecord.options;
    miManualExpandCollapse.checked := moManualExpandCollapse in selectedrecord.options;
    miAlwaysHideChildren.checked := moAlwaysHideChildren in selectedrecord.options;
  end
  else
    miGroupconfig.Visible := False;

  miChangeColor.Visible := addresslist.selcount > 0;

  miUndoValue.Visible := (addresslist.selectedRecord <> nil) and
    (addresslist.selectedRecord.canUndo);

  miSetDropdownOptions.visible:=addresslist.selcount > 0;

  miDBVMFindWhatWritesOrAccesses.visible:={$ifdef windows}Findoutwhataccessesthisaddress1.Visible and isDBVMCapable{$else}false{$endif}; //02/24/2019: Most cpu's support EPT/NP now
  sep2.Visible:=miDBVMFindWhatWritesOrAccesses.Visible;

  miDBVMFindWhatWritesOrAccesses.enabled:={$ifdef windows}DBKLoaded or isRunningDBVM{$else}false{$endif};

  if (selectedrecord<>nil) and (selectedrecord.VarType=vtAutoAssembler) then
  begin
    miAutoAssembleErrorMessage.visible:=selectedrecord.LastAAExecutionFailed;
    if selectedrecord.LastAAExecutionFailed then
      miAutoAssembleErrorMessage.Caption:='<<'+selectedrecord.LastAAExecutionFailedReason+'>>';
  end
  else
  begin
    miAutoAssembleErrorMessage.visible:=false;
    miAutoAssembleErrorMessage.Caption:='';
  end;
end;

procedure TMainForm.foundlistpopupPopup(Sender: TObject);
var bytesize: integer;
  i, last: integer;
  mi: TMenuItem;
begin

  Browsethismemoryregioninthedisassembler1.Enabled := Foundlist3.SelCount >= 1;

  if foundlist3.Items.Count = 0 then
  begin
    Removeselectedaddresses1.Enabled := False;
    Browsethismemoryarrea1.Enabled := False;
    Selectallitems1.Enabled := False;
  end
  else
  begin
    Removeselectedaddresses1.Enabled := True;
    Browsethismemoryarrea1.Enabled := True;

    Selectallitems1.Enabled := foundlist3.Items.Count < 5000;
  end;

  if Foundlist3.SelCount > 1 then
    Removeselectedaddresses1.Caption := rsRemoveSelectedAddresses
  else
    Removeselectedaddresses1.Caption := rsRemoveSelectedAddress;

  if Foundlist3.selcount = 0 then
  begin
    Removeselectedaddresses1.Enabled := False;
    Browsethismemoryarrea1.Enabled := False;
  end
  else
  begin
    Removeselectedaddresses1.Enabled := True;
    Browsethismemoryarrea1.Enabled := True;
  end;

  if Removeselectedaddresses1.enabled then
    Removeselectedaddresses1.enabled := not (GetVarType in [vtBinary, vtByteArray, vtAll]);

  miChangeValue.enabled:=Browsethismemoryarrea1.enabled;
  miChangeValueBack.enabled:=Browsethismemoryarrea1.enabled and (PreviousResultList.count>0);
  miAddAddress.enabled:=Browsethismemoryarrea1.enabled;

  //updatwe the display override
  if memscan<>nil then
    bytesize:=memscan.Getbinarysize div 8
  else
    bytesize:=1; //should never happen

  MenuItem19.visible:=(foundlist3.Items.Count>0) and (memscan<>nil);

  miDisplayDefault.visible:=(foundlist3.Items.Count>0) and (memscan<>nil);

  miDisplayByte.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=1);
  miDisplay2Byte.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=2);
  miDisplay4Byte.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=4);
  miDisplay8Byte.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=8);
  miDisplayFloat.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=4);
  miDisplayDouble.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=8);
  miDisplayHex.visible:=(foundlist3.Items.Count>0) and (memscan<>nil) and (bytesize>=1);

//  miDisplayHex.caption:
  if foundlist<>nil then
  begin
    if foundlist.isHexadecimal then
      miDisplayHex.caption:=rsDecimal
    else
      miDisplayHex.caption:=rsHexadecimal
  end;



  if (foundlist3.Items.Count>0) and (memscan<>nil) then
  begin
    //populate the list with custom types
    last:=foundlistpopup.Items.IndexOf(miDisplayDouble)+1;
    //first delete the current list (new one could have been added)

    while foundlistpopup.Items.Count>last do
      foundlistpopup.Items.Delete(last);

    for i:=0 to customTypes.Count-1 do
    begin
      if TCustomType(customTypes[i]).bytesize<=bytesize then
      begin
        mi:=TMenuItem.Create(foundlistpopup);
        mi.Caption:=TCustomType(customTypes[i]).name;
        mi.RadioItem:=miDisplayDouble.RadioItem;
        mi.AutoCheck:=miDisplayDouble.AutoCheck;
        mi.GroupIndex:=miDisplayDouble.GroupIndex;
        mi.OnClick:=@miChangeDisplayTypeClick;
        mi.tag:=1000+i;
        foundlistpopup.Items.Add(mi);

        if foundlistDisplayOverride=mi.tag then
          mi.Checked:=true;
      end;
    end;


    menuitem14.visible:=(memscan.lastScanWasRegionScan=false) and (memscan.VarType in [vtAll, vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble]);      ;
    miForgotScan.visible:=(memscan.lastScanWasRegionScan=false) and (memscan.VarType in [vtAll, vtByte, vtWord, vtDword, vtQword, vtSingle, vtDouble]);      ;
  end
  else
  begin
    menuitem14.visible:=false;
    miForgotScan.visible:=false;
  end;

  miFlFindWhatAccesses.enabled:=Browsethismemoryarrea1.enabled;
  miFlFindWhatWrites.enabled:=Browsethismemoryarrea1.enabled;

end;

procedure TMainForm.Removeselectedaddresses1Click(Sender: TObject);
var
  e, i, j: integer;
  bit: byte;
  selected: array of integer;
begin
  if SaveFirstScanThread <> nil then
  begin
    SaveFirstScanThread.WaitFor; //wait till it's done
    FreeAndNil(SaveFirstScanThread);
  end;

  for i:=0 to PreviousResultList.count-1 do
    TSavedScanHandler(PreviousResultList[i]).deinitialize;


  if foundlist3.selcount = 1 then //use itemindex (faster)
  begin
    foundlist.deleteaddress(foundlist3.ItemIndex);
  end
  else if foundlist3.selcount > 1 then
  begin
    if foundlist3.items.Count > 100000 then
      if messagedlg(rsThisListIsHuge, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
        exit;

    screen.Cursor := crhourglass;

    //MainForm.Caption := CEWait;
    //Mainform.Refresh;

    foundlist3.Items.BeginUpdate;
    try
      j := 0;
      setlength(selected, foundlist3.selcount);
      for i := 0 to foundlist3.items.Count - 1 do
      begin
        if foundlist3.items[i].Selected then
        begin
          selected[j] := i;
          Inc(j);
        end;
      end;

      for i := length(selected) - 1 downto 0 do
        foundlist.deleteaddress(selected[i]);

    finally
      //Mainform.Caption := CENorm;
      screen.Cursor := crDefault;
      foundlist3.Items.EndUpdate;
    end;
  end;

  foundcount:=foundlist.Reinitialize;

  for i:=0 to PreviousResultList.count-1 do
    TSavedScanHandler(PreviousResultList[i]).reinitialize;

end;



procedure TMainForm.FormClose(Sender: TObject; var cAction: TCloseAction);
var
  i: integer;
  reg: Tregistry;
  crashcounter: integer;

  h: thandle;


begin
  if SyncSymbols and (processid<>0) then
    SyncSymbolsNow;

  i:=0;
  while i<screen.CustomFormCount do
  begin
    if (screen.CustomForms[i] is TCEForm) then
    begin
      screen.CustomForms[i].Free;
    end
    else
      inc(i);
  end;

  {$ifdef windows}
  if adwindow <> nil then
    FreeAndNil(adwindow);
  {$endif}

  //cleanup the user forms
  if formdesigner <> nil then
    formdesigner.Close;

  //undo unrandomize
  if unrandomize <> nil then
    FreeAndNil(unrandomize);

  cbSpeedhack.Checked := False;

  if flashprocessbutton <> nil then
  begin
    flashprocessbutton.Terminate;
    flashprocessbutton.WaitFor;
    FreeAndNil(FlashProcessButton);
  end;
  {$ifdef windows}
  try

    if pointer(@DebugActiveProcessStop) <> pointer(@DebugActiveProcessStopProstitute) then
    begin
      //detach the debugger
      //hide;
      crashcounter := 0;
      if advancedoptions <> nil then
      begin
        if advancedoptions.Pausebutton.Down then
        begin
          advancedoptions.Pausebutton.Down := False;
          advancedoptions.Pausebutton.Click;
        end;
      end;


      if debuggerthread <> nil then
      begin
        debuggerthread.Terminate;
        debuggerthread.WaitFor;
        debuggerthread.Free;
        debuggerthread := nil;
      end;
    end;
  except

  end;
  {$endif}

  if frmProcessWatcher <> nil then
    freeandnil(frmProcessWatcher);

  try
    if tempbitmap<>nil then
      freeandnil(tempbitmap);

    shutdown;

   // unregisterhotkey(handle, 0);
  except

  end;

  if advancedoptions <> nil then
  begin
    if advancedoptions.Pausebutton.Down then
    begin
      with advancedoptions do
      begin
        pausebutton.down := not pausebutton.down;
        pausebutton.Click;
      end;
    end;
  end;

  if length(windowlist) > 0 then
  begin
    toggleWindow;
    setforegroundwindow(lastforeground);
    setactivewindow(lastactive);
  end;

  if autoattachlist<>nil then
    FreeAndNil(autoattachlist);


  if speedhack <> nil then
    FreeAndNil(speedhack);

  if pluginhandler <> nil then
  begin
    pluginhandler.free;
    pluginhandler:=nil;
  end;



  if formsettings.cbSaveMemoryregionScanSettings.checked then
  begin
    //save to the registry
    reg:=tregistry.Create;
    try
      Reg.RootKey := HKEY_CURRENT_USER;
      if Reg.OpenKey('\Software\'+strCheatEngine,true) then
      begin
        reg.WriteInteger('scan CopyOnWrite', integer(cbCopyOnWrite.State));
        reg.WriteInteger('scan Executable', integer(cbExecutable.State));
        reg.WriteInteger('scan Writable', integer(cbWritable.State));

        reg.WriteBool('scan PresentMemoryOnly', cbPresentMemoryOnly.checked);
      end;
    except

    end;

    reg.free;
  end;
end;


procedure TMainForm.CommentButtonClick(Sender: TObject);
begin
  comments.Show;
end;

procedure TMainForm.CopySelectedRecords;
begin
  clipboard.astext := addresslist.GetTableXMLAsText(True);
end;

procedure TMainForm.paste(simplecopypaste: boolean);
{
this routine will paste a entry from the cplipboard into the addresslist of CE
If simplecopypaste is false frmPasteTableentry is shown to let the user change
some stuff before adding the new entry

returns the entry number of the new addresses (first one)
}
var
  s: string;
begin
  s := clipboard.AsText;
  addresslist.AddTableXMLAsText(s, simplecopypaste);
end;

procedure TMainForm.Copy1Click(Sender: TObject);
begin

  copyselectedrecords;
end;

procedure TMainForm.Cut1Click(Sender: TObject);
begin
  copyselectedrecords;
  addresslist.DeleteSelected(False);
end;

procedure TMainForm.Paste1Click(Sender: TObject);
begin
  Paste(formsettings.cbsimplecopypaste.Checked);
end;

procedure TMainForm.DBVMFindWhatWritesOrAccesses(address: ptruint);
var
  res: word;
  id: integer;

  fcd: TFoundCodeDialog;
  unlockaddress: qword;
  canuseept: boolean;

  PA: qword;
begin
  {$ifdef windows}
  if not isRunningDBVM then
    LoadDBK32;

  canuseept:=hasEPTSupport;
  if (isDBVMCapable=false) then
  begin
    messagedlg(rsRequiresDBVMCapableCPU, mtError, [mbok], 0);
    exit;
  end;

  if canuseept=false then
  begin
    messagedlg(rsRequiresEPT, mtError, [mbok], 0);
    exit;
  end;

  if loaddbvmifneeded(rsRequiresDBVMEPT) then
  begin

    if addresslist.selectedRecord <> nil then
    begin
      if addresslist.selectedRecord.IsPointer then
      begin
        with TformPointerOrPointee.Create(self) do
        begin
          btnFindWhatWritesPointer.Caption := rsFindOutWhatAccessesThisPointer;
          btnFindWhatWritesPointee.Caption := rsFindWhatAccessesTheAddressPointedAtByThisPointer;

          res := showmodal;
          if res = mrNo then //find what writes to the address pointer at by this pointer
            address := addresslist.selectedRecord.GetRealAddress
          else
          if res = mrYes then
            address := symhandler.getAddressFromName(
              addresslist.selectedRecord.interpretableaddress)
          else
            exit;
        end;
      end;

      //spawn a DBVM watch config screen where the user can select options like lock memory
      if frmDBVMWatchConfig=nil then
        frmDBVMWatchConfig:=TfrmDBVMWatchConfig.create(self);

      frmDBVMWatchConfig.address:=address;

      if frmDBVMWatchConfig.showmodal=mrok then
      begin

        if frmDBVMWatchConfig.LockPage then
        begin
          LoadDBK32; //this does require the driver
          unlockaddress:=LockMemory(processid, address and QWORD($fffffffffffff000),4096)
        end
        else
          unlockaddress:=0;

        case frmDBVMWatchConfig.watchtype of
          0: id:=dbvm_watch_writes(frmDBVMWatchConfig.PhysicalAddress, addresslist.selectedRecord.bytesize, frmDBVMWatchConfig.Options, frmDBVMWatchConfig.MaxEntries);
          1: id:=dbvm_watch_reads(frmDBVMWatchConfig.PhysicalAddress, addresslist.selectedRecord.bytesize, frmDBVMWatchConfig.Options, frmDBVMWatchConfig.MaxEntries);
          2: id:=dbvm_watch_executes(frmDBVMWatchConfig.PhysicalAddress, addresslist.selectedRecord.bytesize, frmDBVMWatchConfig.Options, frmDBVMWatchConfig.MaxEntries);
          else
            id:=-1;
        end;

        if (id<>-1) then
        begin

          //spawn a foundcodedialog
          fcd:=TFoundCodeDialog.Create(self);
          fcd.multipleRip:=frmDBVMWatchConfig.cbMultipleRIP.Checked;
          fcd.debuggerinterfacewatchid:=id;
          fcd.dbvmwatch_unlock:=unlockaddress;
          case frmDBVMWatchConfig.watchtype of
            0: fcd.caption:=Format(rsTheFollowingOpcodesAccessed, [inttohex(address, 8)]);
            1: fcd.caption:=Format(rsTheFollowingOpcodesWriteTo, [inttohex(address, 8)]);
            2: fcd.caption:=Format(rsTheFollowingAddressesExecute, [inttohex(address, 8)]);
          end;


          fcd.show;
        end
        else
        begin
          MessageDlg(rsDbvmWatchFailed, mtError, [mbok], 0);
          if unlockaddress<>0 then
            UnlockMemory(unlockaddress);
        end;

      end;
      freeandnil(frmDBVMWatchConfig);


    end;
  end;

  {$endif}
end;

procedure TMainForm.miDBVMFindWhatWritesOrAccessesClick(Sender: TObject);
var address: ptruint;
begin
  address := addresslist.selectedRecord.GetRealAddress;
  DBVMFindWhatWritesOrAccesses(address);
end;

procedure TMainForm.miAlwaysHideChildrenClick(Sender: TObject);
begin
  miAlwaysHideChildren.Checked := not miAlwaysHideChildren.Checked;

  if addresslist.selectedRecord <> nil then
  begin
    if miAlwaysHideChildren.Checked then
      addresslist.selectedRecord.options := addresslist.selectedRecord.options + [moAlwaysHideChildren]
    else
      addresslist.selectedRecord.options := addresslist.selectedRecord.options - [moAlwaysHideChildren];
  end;
end;

procedure TMainForm.miNetworkClick(Sender: TObject);
begin
  updateNetworkOptions;
end;

type
  TCEServerOptionMenuItemData=class
    data: TCEServerOption;
  end;

  TCEServerOptionMenuItemValue=class
    value: string;
  end;

procedure TMainForm.updateNetworkOption(sender: TObject);
var
  mi: TMenuItem absolute sender;
  data:  TCEServerOptionMenuItemData;
  value: TCEServerOptionMenuItemValue;
  v: string;
  c: TCEConnection;
begin

  if (sender is TMenuItem) then
  begin
    if tobject(mi.tag) is TCEServerOptionMenuItemValue then
    begin
      value:=TCEServerOptionMenuItemValue(mi.tag);
      data:=TCEServerOptionMenuItemData(mi.Parent.Tag);

      v:=value.value;

      c:=getConnection;
      if c<>nil then
      begin
        c.setOption(data.data.optname, v);
      end;
    end
    else
    begin
      data:=TCEServerOptionMenuItemData(mi.tag);
      if data.data.optiontype=netBoolean then
      begin
        if mi.checked then v:='1' else v:='0';
      end
      else
      begin
        v:=data.data.currentvalue;
        if InputQuery(rsNetworkOption+data.data.optname, rsChangeValue, v)<>true
          then exit;
      end;

      c:=getConnection;
      if c<>nil then
      begin
        c.setOption(data.data.optname, v);
        data.data.currentvalue:=c.getOption(data.data.optname);

        mi.OnClick:=nil;
        if data.data.optiontype=netBoolean then
          mi.checked:=data.data.currentvalue='1'
        else
          mi.caption:=data.data.optdescription+' : '+data.data.currentvalue;

        mi.OnClick:=@updateNetworkOption;
      end;
    end;
  end;
end;

procedure TMainForm.updateNetworkOptions;
var
  i,j: integer;
  ol: TCEServerOptions;

  mi: TMenuItem;
  smi: TMenuItem;
  data: TCEServerOptionMenuItemData;
  value: TCEServerOptionMenuItemValue;
  sl: TStringlist;

  v: array of string;
begin
  //fetch the current available ceserver options, and show them in the menu
  while miNetwork.Count>3 do
  begin
    if tobject(miNetwork.items[3].Tag) is TObject then
      TObject(miNetwork.items[3].Tag).free;

    miNetwork.Items[3].Free;
  end;

  ol:=[];
  getConnection.getOptions(ol);

  for i:=0 to length(ol)-1 do
  begin
    mi:=TMenuItem.Create(self);
    mi.Caption:=ol[i].optdescription;

    data:=TCEServerOptionMenuItemData.create;
    data.data:=ol[i];
    mi.Tag:=ptruint(data);


    if ol[i].optiontype=netParent then
    begin
      //nothing else
    end
    else
    begin
      mi.onclick:=@updateNetworkOption;
      if ol[i].optiontype=netBoolean then
      begin
        mi.AutoCheck:=true;
        mi.checked:=ol[i].currentvalue='1';
      end
      else
      begin

        if ol[i].acceptablevalues<>'' then
        begin
          mi.onclick:=nil;
          //turn the options into subitems
          sl:=TStringList.Create;
          sl.LineBreak:=';';
          sl.Text:=ol[i].acceptablevalues;

          for j:=0 to sl.Count-1 do
          begin
            v:=sl[j].Split('=');
            value:=TCEServerOptionMenuItemValue.Create;
            value.value:=v[0];

            smi:=TMenuItem.create(self);
            smi.Caption:=v[1];
            smi.RadioItem:=true;
            smi.GroupIndex:=i+1;
            smi.checked:=ol[i].currentvalue=v[0];
            smi.tag:=ptruint(value);
            smi.AutoCheck:=true;

            smi.onclick:=@updateNetworkOption;

            mi.Add(smi);
          end;

          sl.free;
        end
        else
          mi.caption:=mi.caption+' : '+ol[i].currentvalue;
      end;
    end;

    if ol[i].parentoptname<>'' then
    begin
      for j:=0 to miNetwork.count-1 do
      begin
        if (tobject(miNetwork.items[j].Tag) is TCEServerOptionMenuItemData) and (TCEServerOptionMenuItemData(miNetwork.items[j].Tag).data.optname=ol[i].parentoptname) then
        begin
          miNetwork.items[j].Add(mi);
          break;
        end;
      end;
    end
    else
      miNetwork.Add(mi);
  end;

end;

procedure TMainForm.miNetworkReadUseProcMemClick(Sender: TObject);
begin

end;

procedure TMainForm.miOnlyShowCurrentCompareToColumnClick(Sender: TObject);
begin
  ActivePreviousResultColumn:=ActivePreviousResultColumn;
  cereg.writeBool('Only show current compare column', miOnlyShowCurrentCompareToColumn.Checked);

  Panel5Resize(nil);
end;

procedure TMainForm.Findoutwhataccessesthisaddress1Click(Sender: TObject);
var
  address: ptrUint;
  res: word;
begin
  if addresslist.selectedRecord <> nil then
  begin
    address := addresslist.selectedRecord.GetRealAddress;
    if (not startdebuggerifneeded) then
      exit;

    if addresslist.selectedRecord.IsPointer then
    begin
      with TformPointerOrPointee.Create(self) do
      begin
        btnFindWhatWritesPointer.Caption := rsFindOutWhatAccessesThisPointer;
        btnFindWhatWritesPointee.Caption := rsFindWhatAccessesTheAddressPointedAtByThisPointer;

        res := showmodal;
        if res = mrNo then //find what writes to the address pointer at by this pointer
          address := addresslist.selectedRecord.GetRealAddress
        else
        if res = mrYes then
        begin
          addresslist.selectedRecord.parseAddressString(addresslist.selectedRecord.interpretableaddress, address);
        end
        else
          exit;
      end;
    end;

    DebuggerThread.FindWhatAccesses(address, addresslist.selectedRecord.bytesize); //byte

  end;
end;

procedure TMainForm.Setbreakpoint1Click(Sender: TObject);
var
  address: ptrUint;
  res: word;
begin
  OutputDebugString('Setbreakpoint1Click');

  if addresslist.selectedRecord <> nil then
  begin
    address := addresslist.selectedRecord.GetRealAddress;

    if (not startdebuggerifneeded) then
      exit;

    if addresslist.selectedRecord.IsPointer then
    begin
      with TformPointerOrPointee.Create(self) do
      begin
        btnFindWhatWritesPointer.Caption := rsFindOutWhatWritesThisPointer;
        btnFindWhatWritesPointee.Caption := rsFindWhatWritesTheAddressPointedAtByThisPointer;

        res := showmodal;
        if res = mrNo then //find what writes to the address pointer at by this pointer
          address := addresslist.selectedRecord.GetRealAddress
        else
        if res = mrYes then
        begin
          addresslist.selectedRecord.parseAddressString(addresslist.selectedRecord.interpretableaddress, address);
        end
        else
          exit;
      end;
    end;

    DebuggerThread.FindWhatWrites(address, addresslist.selectedRecord.bytesize);

    //debug
   //debuggerthread.SetOnWriteBreakpoint(address, addresslist.selectedRecord.bytesize, bpmException);

  end;
end;

procedure TMainForm.TopDisablerTimer(Sender: TObject);
begin
  setwindowpos(mainform.Handle, HWND_NOTOPMOST, mainform.left, mainform.top,
    mainform.Width, mainform.Height, SWP_SHOWWINDOW);
  TopDisabler.Enabled := False;
end;

procedure TMainForm.advancedbuttonClick(Sender: TObject);
begin
  advancedoptions.Show;
end;

procedure TMainForm.cbHexadecimalClick(Sender: TObject);
var
  x: qword;
  i: integer;
begin

  if dontconvert then
    exit;

  if cbHexadecimal.Checked then
  begin
    //convert what is in scanvalue to hexadecimal notation
    val(scanvalue.Text, x, i);
    case GetVarType of
      vtByte: scanvalue.Text := IntToHex(byte(x), 2);
      vtWord: scanvalue.Text := inttohex(word(x), 4);
      vtDword: scanvalue.Text := inttohex(dword(x), 8);
      vtQword: scanvalue.Text := inttohex(qword(x), 16);
    end;

  end
  else
  begin
    //convert to decimal notation
    case GetVarType of
      vtByte, vtWord, vtDword, vtQWord:
      begin
        if length(scanvalue.Text) > 0 then
        begin
          if scanvalue.Text[1] = '-' then
            val('-$' + copy(scanvalue.Text, 2, length(scanvalue.Text)), x, i)
          else
            val('$' + scanvalue.Text, x, i);

          scanvalue.Text := IntToStr(x);
        end;
      end;
    end;
  end;
end;

procedure TMainForm.SetHotkey1Click(Sender: TObject);
begin
  {  HotKeyForm.recnr:=lastselected;}
  if addresslist.selectedRecord=nil then exit;
  if addresslist.selectedRecord.isBeingEdited then
    exit;

  with THotKeyForm.Create(self) do
  begin
    memrec := addresslist.selectedRecord;
    if memrec<>nil then
    begin
      memrec.beginEdit;
      Show;
    end;
  end;
end;


procedure TMainForm.UndoScanClick(Sender: TObject);
var
  i, j: integer;
  error: integer;
  a, b: string;

begin

  if (sender=undoscan) or (messagedlg(strConfirmUndo, mtConfirmation, [mbYes, mbNo], 0) = mrYes) then
  begin
    foundlist3.BeginUpdate;
    cleanupPreviousResults;

    foundlist.Deinitialize;
    memscan.undolastscan;
    foundcount := foundlist.Initialize(getvartype, memscan.CustomType);

    reloadPreviousResults;

    undoscan.Enabled := False;
    foundlist3.EndUpdate;
  end;
end;

procedure TMainForm.adjustbringtofronttext;
var
  hk: string;
  reg: TRegistry;

begin
  if formsettings.frameHotkeyConfig.cbHideAllWindows.Checked then
  begin
    if allwindowsareback then
    begin
      if onlyfront then
        fronttext := strHideForeground
      else
        fronttext := strHideAll;
    end
    else
    begin
      if onlyfront then
        fronttext := strUnhideForeground
      else
        fronttext := strUnhideAll;
    end;

  end
  else
    fronttext := rsBringsCheatEngineToFront;


  hk:=cereg.readString('BringToFrontHotkey');
end;




procedure TMainForm.FormShow(Sender: TObject);


var
  reg: tregistry;
  modifier: dword;
  key: dword;
  hk: string;
  year, month, day: word;
  temp: string;

  i,j: integer;
  outputfile: textfile;
  go: boolean;
  loadt: boolean;

  firsttime: boolean;
  x: array of integer;

  t: tcomponent;


  ReferenceControl: TControl;
  ReferenceSide : TAnchorSideReference;

  c: TControl;

  logopic: TPicture;
  rs: TResourceStream;
  cleanrun: boolean;

  {$ifdef windows}
  cbi: TComboboxInfo;
  {$endif}
  extrasize: integer;
  s: string;

  rname: string;
begin
  if onetimeonly then
    exit;



  fontmultiplication:=ProcessLabel.Height/15; //normal dpi/font settings have this at 15.

  screen.HintFont:=font;


  onetimeonly := True;
  {$if defined(CPU386) or defined(CPUX86_64)}
  Set8087CW($133f);
  SetSSECSR($1f80);
  {$endif}

  loadt := False;
  editsh2.Text := format('%.1f', [1.0]);


  reg := Tregistry.Create;
  try
    Reg.RootKey := HKEY_CURRENT_USER;

    if not Reg.OpenKey('\Software\'+strCheatEngine, False) then //can't be opened. Clean install
    begin
      if Reg.OpenKey('\Software\'+strCheatEngine, True) then
      begin
        //write some default data into the registry
        reg.WriteBool('Undo', True);
        reg.writeBool('Advanced', True);

        reg.WriteInteger('ScanThreadpriority',
          formsettings.combothreadpriority.ItemIndex);
      end;
    end;
  except

  end;

  if reg.ValueExists('First Time User') then
    firsttime := reg.ReadBool('First Time User')
  else
    firsttime := True;

  if firsttime then
  begin
    reg.WriteBool('First Time User', False);


    if formsettings.lbLanguages.Count>1 then
    begin
      i:=ShowSelectionList(self, rsLanguage, rsChooseLanguage, formSettings.lbLanguages.Items, s);
      if i<>-1 then
      begin
        formSettings.lbLanguages.ItemIndex:=i;
        formsettings.btnSelectLanguage.Click;
      end;
    end;


    if messagedlg(rsTryTutorial, mtConfirmation, [mbYes, mbNo], 0) = mrYes then
    {$ifdef darwin}
      miTutorial64.click;
    {$else}
      {$ifdef cpu32}
      miTutorial.Click;
      {$else}
      miTutorial64.Click;
      {$endif}
    {$endif}
  end;

  if reg.ValueExists('Show previous value column') then
  begin
    miShowPreviousValue.checked:=reg.ReadBool('Show previous value column');
    miShowPreviousValueClick(miShowPreviousValue);
  end;

  if reg.ValueExists('Only show current compare column') then
    miOnlyShowCurrentCompareToColumn.checked:=reg.ReadBool('Only show current compare column');


  //  animatewindow(mainform.Handle,10000,AW_CENTER);
  //mainform.repaint;
  fronttext := rsBringsCheatEngineToFront;

  if dontrunshow then
    exit;

  panel7.DoubleBuffered := True;
  flashprocessbutton := tflash.Create(False);



  dontrunshow := True;
  decodedate(now, year, month, day);
  if (month = 7) and (day = 1) then
    ShowMessage(strhappybirthday);
  if (month = 1) and (day = 1) then
  begin
    if reg.ValueExists('ShownHappyNewYear'+inttostr(year))=false then
    begin
      ShowMessage(strnewyear);
      reg.WriteBool('ShownHappyNewYear'+inttostr(year), true);
    end;
  end;
  if (month = 1) and (day = 1) and (year >= 2030) then
    ShowMessage(strFuture);

  if (month = 4) and (day = 1) then
    aprilfools := True;


  //aprilfools:=true;
  {$ifdef windows}
  if aprilfools then  //what whould happen if this var is false?
  begin
    if copy(cenorm,1,5)='Cheat' then
    begin
      cenorm[3]:='E';
      cenorm[4]:='A';
      caption:=cenorm;
    end;
    EnableCheatECoinSystem;
  end;
  {$endif}


  //Load the table if one was suplied
  overridedebug := False;


  if (GetSystemType < 4) {or (is64bitos)} then  //not nt or later
  begin
    with formsettings do
    begin
      cbKernelQueryMemoryRegion.Enabled := False;
      cbKernelReadWriteProcessMemory.Enabled := False;
      cbKernelOpenProcess.Enabled := False;
      cbProcessWatcher.Enabled := False;
      cbKDebug.Enabled := False;
      cbGlobalDebug.Enabled := False;

      TauntOldOsUser.Visible := True;
    end;
  end;



  vartypechange(vartype);
  adjustbringtofronttext;

   {
  if aprilfools then
    Caption := cenorm + ' ' + rsEXPIRED + '!';}

  if autoattachtimer.Enabled then
    autoattachcheck
  else
    AutoAttachThread:=TAutoAttachThread.Create(false);




  //SMenu:=GetSystemMenu(handle,false);
  cleanrun:=autosize;
  autosize:=false;


  memscan := tmemscan.Create(ProgressBar);
  memscan.GuiScanner:=true;
  memscan.OnGuiUpdate:=@MemscanGuiUpdate;
  memscan.OnInitialScanDone:=@MemScanDone;
  memscan.OnScanStart:=@MemScanStart;

  foundlist := tfoundlist.Create(foundlist3, memscan);


  logo.Width:=settingsbutton.width;

  {$ifdef altname}
  rname:='IMAGES_ALT_CELOGO';
  {$else}
  rname:='IMAGES_CELOGO';
  {$endif}

  {$ifdef windows}
  {$ifndef altname}
  if logo.Width>=90 then
  {$endif}
  {$endif}
  begin
    rs := TResourceStream.Create(HInstance, rname, RT_RCDATA);
    logopic:=TPicture.Create;
    logopic.LoadFromStreamWithFileExt(rs,'.PNG');
    logo.Picture:=logopic;
    logo.Stretch:=true;


    logopic.free;
    freeandnil(rs);
  end;

  if settingsbutton.Width>logo.Picture.Width then
    logo.Width:=settingsbutton.width;

  if logo.Width>=80 then
  begin
    rs := TResourceStream.Create(HInstance, rname, RT_RCDATA);
    logopic:=TPicture.Create;
    logopic.LoadFromStreamWithFileExt(rs,'.PNG');
    logo.Picture:=logopic;
    logo.Stretch:=true;


    logopic.free;
    freeandnil(rs);
  end;

  logo.Height:=trunc((logo.Width / logo.picture.Width)*logo.picture.Height);

  sbOpenProcess.BorderSpacing.Around:=ScaleX(sbOpenProcess.BorderSpacing.Around, 96);
  loadbutton.BorderSpacing.Top:=sbOpenProcess.BorderSpacing.Around;


  //because the images have no empty border autosize is out of the question as that makes them hug the border. So, scale them manually
  sbOpenProcess.Width:=scalex(sbOpenProcess.Width, 96);
  sbOpenProcess.Height:=scaley(sbOpenProcess.Height, 96);

  LoadButton.Width:=scalex(LoadButton.Width, 96);
  LoadButton.Height:=scaley(LoadButton.Height, 96);

  SaveButton.Width:=scalex(SaveButton.Width, 96);
  SaveButton.Height:=scaley(SaveButton.Height, 96);

  SpeedButton2.Width:=scalex(SpeedButton2.Width, 96);
  SpeedButton2.Height:=scaley(SpeedButton2.Height, 96);

  SpeedButton3.Width:=scalex(SpeedButton3.Width, 96);
  SpeedButton3.Height:=scaley(SpeedButton3.Height, 96);


  if panel7.Height>ProgressBar.Top+ProgressBar.Height then
    label6.AnchorSideTop.Control:=panel7
  else
    label6.AnchorSideTop.Control:=ProgressBar;


  panel5resize(panel5);

  {$ifdef windows}
  if WindowsVersion>=wvVista then
  begin
    i:=sendmessage(scanvalue.Handle, EM_GETMARGINS, 0,0);
    i:=(i shr 16)+(i and $ffff);
  end
  else
  {$endif}
    i:=8;

  editSH2.Constraints.MinWidth:=canvas.TextWidth('500.0 ')+i;


  edtAlignment.Constraints.MinWidth:=canvas.TextWidth('XXXX');
  edtAlignment.Constraints.MaxWidth:=canvas.TextWidth('XXXXX');

  panel6.clientheight:=cbPauseWhileScanning.top+cbPauseWhileScanning.height+2;
  gbScanOptions.ClientHeight:=panel6.top+panel6.height+2;

  fromaddress.font.name:='Courier';
  toaddress.font.name:='Courier';
  i:=GetFontData(font.Handle).Height;
  fromaddress.Font.Height:=i;
  toaddress.Font.Height:=i;

  if Reg.OpenKey('\Software\'+strCheatEngine+'\FoundList'+darkmodestring, false) then
  begin
    if reg.ValueExists('FoundList.NormalValueColor') then foundlistcolors.NormalValueColor:=reg.ReadInteger('FoundList.NormalValueColor');
    if reg.ValueExists('FoundList.ChangedValueColor') then foundlistcolors.ChangedValueColor:=reg.ReadInteger('FoundList.ChangedValueColor');
    if reg.ValueExists('FoundList.StaticColor') then foundlistcolors.StaticColor:=reg.ReadInteger('FoundList.StaticColor');
    if reg.ValueExists('FoundList.DynamicColor') then foundlistcolors.DynamicColor:=reg.ReadInteger('FoundList.DynamicColor');
    if reg.ValueExists('FoundList.BackgroundColor') then foundlist3.color:=reg.ReadInteger('FoundList.BackgroundColor');
    if reg.ValueExists('FoundList.CompareToHeaderColor') then foundlistcolors.compareToHeadercolor:=reg.ReadInteger('FoundList.CompareToHeaderColor');
    if reg.ValueExists('FoundList.ShowStaticAsStatic') then showStaticAsStatic:=reg.ReadBool('FoundList.ShowStaticAsStatic');
    if reg.ValueExists('FoundList.OverrideFontSize') then AddressListOverrideFontSize:=reg.ReadBool('FoundList.OverrideFontSize');

    LoadFontFromRegistry(foundlist3.font,reg);
    if not AddressListOverrideFontSize then Foundlist3.Font.Height:=i;
  end
  else
  begin
    foundlistColors.NormalValueColor:=clWindowtext;
    foundlistColors.ChangedValueColor:=clRed;
    foundlistColors.StaticColor:=clGreen;
    foundlistColors.DynamicColor:=clWindowtext;
    foundlistColors.CompareToHeaderColor:=clGreen;

    showStaticAsStatic:=true;
    Foundlist3.Font.Height:=i;
  end;
  freeandnil(reg);


  btnNewScan.autosize:=true;
  btnNextScan.AutoSize:=true;
  btnNewScan.autosize:=false;
  btnNextScan.AutoSize:=false;

  i:=max(btnNewScan.Width, btnNextScan.Width);
  btnNewScan.width:=i;
  btnNextScan.width:=i;

  btnAddAddressManually.autosize:=true;
  btnAddAddressManually.autosize:=false;
  btnMemoryView.autosize:=true;
  btnMemoryView.autosize:=false;
  i:=max(btnAddAddressManually.Width, btnMemoryView.Width);
  btnAddAddressManually.width:=i;
  btnMemoryView.width:=i;

  i:=canvas.TextHeight('ygGxX');
  btnAddAddressManually.ClientHeight:=i+4;
  btnMemoryView.ClientHeight:=i+4;


  {$ifdef windows}
  cbi.cbSize:=sizeof(cbi);
  if GetComboBoxInfo(vartype.handle, @cbi) then
    extrasize:=cbi.rcButton.Right-cbi.rcButton.Left+cbi.rcItem.Left
  else
  {$endif}
    extrasize:=16;

  i:=Canvas.TextWidth(rsMUGenerateGroupscanCommand)+extrasize;
  i:=max(i, Canvas.TextWidth(strExactValue)+extrasize);
  i:=max(i, Canvas.TextWidth(strBiggerThan)+extrasize);
  i:=max(i, Canvas.TextWidth(strsmallerThan)+extrasize);
  i:=max(i, Canvas.TextWidth(strValueBetween)+extrasize);
  i:=max(i, Canvas.TextWidth(strUnknownInitialValue)+extrasize);
  i:=max(i, Canvas.TextWidth(strIncreasedValue)+extrasize);
  i:=max(i, Canvas.TextWidth(strIncreasedValueBy)+extrasize);
  i:=max(i, Canvas.TextWidth(strDecreasedValue)+extrasize);
  i:=max(i, Canvas.TextWidth(strDecreasedValueBy)+extrasize);
  i:=max(i, Canvas.TextWidth(strChangedValue)+extrasize);
  i:=max(i, Canvas.TextWidth(strUnchangedValue)+extrasize);
  i:=max(i, Canvas.TextWidth(strCompareToLastScan)+extrasize);
  i:=max(i, Canvas.TextWidth(strCompareToFirstScan)+extrasize);
  i:=max(i, Canvas.TextWidth(strcompareToSavedScan)+extrasize);

  vartype.Constraints.MinWidth:=i;

  i:=foundlist3.width;
  if undoscan.visible and (undoscan.left<btnNextScan.Left+btnNextScan.Width) then
  begin
    j:=(btnNextScan.Left+btnNextScan.Width)-undoscan.left;
    i:=foundlist3.width-j;
  end;

  pnlFloat.Visible:=true;
  panel9.Constraints.MinWidth:=panel9.Width;
  pnlFloat.Visible:=false;



  pnlScanOptions.Constraints.MinHeight:=gbScanOptions.Top-panel9.top;
  panel10.Constraints.MinWidth:=max(panel14.Width, panel10.Width);

  pnlScanValueOptions.Constraints.MinHeight:=rbBit.Height+rbDec.height;
  pnlScanValueOptions.Constraints.MinWidth:=max(rbDec.width, rbBit.width);

  if i>pnlScanValueOptions.left then
    i:=pnlScanValueOptions.left-4;

  if i>lblValueType.left then
    i:=lblValueType.left-4;

  if i>gbScanOptions.left then
    i:=gbScanOptions.left-4;

  if i+speedbutton3.Width>gbScanOptions.left then
    dec(i, (i+speedbutton3.Width)-gbScanOptions.left)
  else
  begin
    gbScanOptions.AnchorSideLeft.Control:=speedbutton3;
    gbScanOptions.AnchorSideLeft.Side:=asrRight;
    gbScanOptions.Anchors:=gbScanOptions.Anchors+[akLeft];
  end;

  if i<0 then
  begin
    clientwidth:=clientwidth+(-i);
    foundlist3.width:=1;
  end
  else
    foundlist3.width:=i;



  if speedbutton2.top<btnMemoryView.Top then
    foundlist3.AnchorSideBottom.Control:=speedbutton2;


  lblcompareToSavedScan.left:=btnNewScan.left-(lblcompareToSavedScan.Width div 2)+((btnNextScan.left+btnNextScan.Width-btnNewScan.left) div 2);

  ProgressBar.height:=scaley(ProgressBar.height, 96);

  i:=((logopanel.Top+logopanel.height)-scanvalue.top)+2;
  if i>0 then
    scantext.BorderSpacing.Top:=scantext.BorderSpacing.Top+i;

  if pnlScanValueOptions.top+pnlScanValueOptions.Height>scanvalue.top+scanvalue.height then
    scantype.AnchorSideTop.Control:=pnlScanValueOptions
  else
  begin
    scantype.AnchorSideTop.Control:=scanvalue;
    scantype.BorderSpacing.Top:=2;
  end;

  panel9.borderspacing.Top:=(scantype.height div 2)-(cbNot.Height div 2);

  if cleanrun then //clean setup
  begin
    foundlist3.Column[0].AutoSize:=true;
    foundlist3.Column[1].AutoSize:=true;
    foundlist3.Column[2].AutoSize:=true;

    j:=max(foundlist3.canvas.textwidth('DDDDDDDDDDDDD'), foundlist3.Column[0].Width);

    foundlist3.Column[0].AutoSize:=false;
    foundlist3.Column[0].Width:=j;

    i:=j+foundlist3.Column[1].Width+foundlist3.Column[2].Width  ;


    foundlist3.Column[1].AutoSize:=false;
    foundlist3.Column[2].AutoSize:=false;

    if foundlist3.clientWidth<i then
      width:=width+(i-foundlist3.clientWidth);

    i:=panel5.Height+splitter1.height+addresslist.headers.Height+btnNewScan.Height*4;
    if clientheight<i then
      clientheight:=i;

    self.position:=poDesigned;
    self.position:=poScreenCenter;

    i:=addresslist.headers.Canvas.TextWidth(addresslist.headers.Sections[0].Text+' ');
    if i>addresslist.headers.Sections[0].Width then addresslist.headers.Sections[0].Width:=i;

    i:=max(addresslist.headers.Canvas.TextWidth(addresslist.headers.Sections[1].Text), addresslist.headers.Canvas.TextWidth(strNoDescription));
    if i>addresslist.headers.Sections[1].Width then addresslist.headers.Sections[1].Width:=i;

    i:=max(addresslist.headers.Canvas.TextWidth(addresslist.headers.Sections[2].Text), addresslist.headers.Canvas.TextWidth('P->DDDDDDDDDDDD'));
    if i>addresslist.headers.Sections[2].Width then addresslist.headers.Sections[2].Width:=i;

    i:=max(addresslist.headers.Canvas.TextWidth(addresslist.headers.Sections[3].Text), addresslist.headers.Canvas.TextWidth(rs_vtByteArray));
    if i>addresslist.headers.Sections[3].Width then addresslist.headers.Sections[3].Width:=i;


    //initial state: focus on the addresslist
    panel5.height:=gbScanOptions.top+gbScanOptions.Height;

    i:=12*addresslist.Items.Owner.DefaultItemHeight;
    j:=addresslist.height;
    if i>j then
    begin
      i:=clientheight+(i-addresslist.height);
      clientheight:=i;
    end;
  end;

  panel5.OnResize(panel5);

  gbScanOptionsChangeBounds(panel5);


  btnSetSpeedhack2.AutoSize:=false;
  btnSetSpeedhack2.Height:=btnAddAddressManually.Height;

  scantype.Anchors:=[akRight];
  scantype.AnchorSideTop.Control:=nil;
  scantype.Anchors:=[akRight, akTop];

  if not memscan.canWriteResults then
    MessageDlg(Format(rsInvalidScanFolder, [memscan.GetScanFolder]), mtError, [mbOk], 0);

 // ImageList2.GetBitmap(0);

  case cereg.readInteger('Last Rounding Type',1) of
    0: rt1.checked:=true;
    1: rt2.checked:=true;
    2: rt3.checked:=true;
  end;

  ActivePreviousResultColumn:=2;

  if runningAsAdmin then
    caption:=caption+' (Admin)';

  askAboutRunningAsAdmin:=true;

end;



procedure TMainForm.rbBitClick(Sender: TObject);
begin

  if not isbit then
  begin
    isbit := True;
    //convert the value to a binary value
    try
      if scanvalue.Text = '' then
        scanvalue.Text := '0'
      else
        scanvalue.Text := parsers.inttobin(StrToQWordEx(scanvalue.Text));
      if scanvalue.Text = '' then
        scanvalue.Text := '0';
    except

    end;
  end;

end;

procedure TMainForm.rbDecClick(Sender: TObject);
begin
  if isbit then
  begin
    isbit := False;
    //convert the binary text to a decimal representation
    scanvalue.Text := IntToStr(parsers.BinToInt(scanvalue.Text));
  end;
end;

procedure TMainForm.Cut2Click(Sender: TObject);
var e: TEdit;
begin
  e:=nil;
  if scanvalue.Focused then e:=scanvalue;
  if (scanvalue2<>nil) and scanvalue2.Focused then e:=scanvalue2;
  if e=nil then exit;

  if e.SelLength > 0 then
    e.CutToClipboard;
end;

procedure TMainForm.Copy2Click(Sender: TObject);
var e: tedit;
begin
  e:=nil;
  if scanvalue.Focused then e:=scanvalue;
  if (scanvalue2<>nil) and scanvalue2.Focused then e:=scanvalue2;

  if e=nil then exit;

  if e.SelLength > 0 then
    e.CopyToClipboard;
end;

procedure TMainForm.Paste2Click(Sender: TObject);
var
  cb: TClipboard;
  i: integer;
  allow: boolean;
  e: tedit;
begin
  cb := tclipboard.Create;
  try
    if cb.HasFormat(CF_TEXT) then
    begin
      e:=nil;
      if scanvalue.Focused then e:=scanvalue;
      if (scanvalue2<>nil) and scanvalue2.Focused then e:=scanvalue2;

      if e=nil then exit;

      e.PasteFromClipboard;
    end;
  finally
    cb.Free;
  end;
end;

procedure TMainForm.checkpaste;
var
  cb: TClipboard;
  i: integer;
  allow: boolean;
begin
  cb := tclipboard.Create;
  Paste2.Enabled := cb.HasFormat(CF_TEXT);
  cb.Free;
end;

procedure TMainForm.ccpmenuPopup(Sender: TObject);
begin
  checkpaste;
end;

procedure TMainForm.Splitter1Moved(Sender: TObject);
begin
  panel5.Repaint;
end;

procedure TMainForm.SettingsClick(Sender: TObject);
var

  oldScanDone, oldInitialScanDone, oldScanStart: TNotifyEvent;
  oldKernelQueryMemoryRegion, oldKernelReadWriteProcessMemory, oldKernelOpenProcess: boolean;
begin

  suspendhotkeyhandler;


  oldKernelQueryMemoryRegion:=formsettings.cbKernelQueryMemoryRegion.Checked;
  oldKernelReadWriteProcessMemory:=formsettings.cbKernelReadWriteProcessMemory.Checked;
  oldKernelOpenProcess:=formsettings.cbKernelOpenProcess.Checked;

  if formsettings.ShowModal <> mrOk then
  begin
    resumehotkeyhandler;
    LoadSettingsFromRegistry(true, true);
    exit;
  end;


  resumehotkeyhandler;

  {$ifdef windows}

  if oldKernelQueryMemoryRegion<>formsettings.cbKernelQueryMemoryRegion.Checked then
  begin
    if formsettings.cbKernelQueryMemoryRegion.Checked then
      UseDBKQueryMemoryRegion
    else
      DontUseDBKQueryMemoryRegion;
  end;

  if oldKernelReadWriteProcessMemory<>formsettings.cbKernelReadWriteProcessMemory.Checked then
  begin
    if formsettings.cbKernelReadWriteProcessMemory.Checked then
      UseDBKReadWriteMemory
    else
      DontUseDBKReadWriteMemory;
  end;

  if oldKernelOpenProcess<>formsettings.cbKernelOpenProcess.Checked then
  begin
    if formsettings.cbKernelOpenProcess.Checked then
      UseDBKOpenProcess
    else
      DontUseDBKOpenProcess;
  end;
  {$endif}

  adjustbringtofronttext;

  if not btnNextScan.Enabled then
  begin
    //memscan can be reset
    if memscan <> nil then
    begin
      oldScanDone:=memscan.OnScanDone;
      oldScanStart:=memscan.OnScanStart;
      oldInitialScanDone:=memscan.OnInitialScanDone;
      memscan.Free;
    end
    else
    begin
      oldScanDone:=nil;
      oldScanStart:=@MemScanStart;
      oldInitialScanDone:=@MemScanDone;
    end;

    memscan := tmemscan.Create(ProgressBar);
    memscan.GuiScanner:=true;
    memscan.OnScanStart:=@memscanStart;
    memscan.OnGuiUpdate:=@memscanGuiUpdate;
    memscan.OnScanDone:=oldScanDone;
    memscan.OnScanStart:=oldScanStart;
    memscan.OnInitialScanDone:=oldInitialScanDone;
  end;
end;

procedure TMainForm.cbCaseSensitiveClick(Sender: TObject);
begin
  cbHexadecimal.Checked := cbcasesensitive.Checked;
end;

procedure TMainForm.LogoMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: integer);
begin
  if button = mbright then
    miAbout.click;
end;


procedure TMainForm.OpenProcesslist1Click(Sender: TObject);
begin
  sbOpenProcess.Click;
end;

procedure TMainForm.CloseCheatEngine1Click(Sender: TObject);
begin
  Close;
end;

procedure TMainForm.Showashexadecimal1Click(Sender: TObject);
var
  i: integer;
  newstate: boolean;
begin
  if addresslist.selectedRecord <> nil then
  begin
    newstate := not addresslist.selectedRecord.showAsHex;

    for i := 0 to addresslist.Count - 1 do
      if addresslist[i].isSelected then
        addresslist[i].showAsHex := newstate;
  end;
end;

procedure TMainForm.OpenMemorybrowser1Click(Sender: TObject);
begin
  btnMemoryView.click;
end;

procedure TMainForm.cbSaferPhysicalMemoryChange(sender: tobject);
begin
  {$ifdef windows}
  DBK32functions.saferQueryPhysicalMemory:=cbsaferPhysicalMemory.checked;
  {$endif}
end;

procedure TMainForm.cbPauseWhileScanningClick(Sender: TObject);

begin
  if (cbPauseWhileScanning.Checked) and (processid = getcurrentprocessid) then
  begin
    cbPauseWhileScanning.Checked := False;
    messagedlg(strdontbother, mtError, [mbOK], 0);
  end;
end;

procedure TMainForm.ProcessLabelDblClick(Sender: TObject);
var
  peprocess: dword;
  needed: dword;
  x: dword;
  processInfo: TProcessBasicInformation;

  buf: PChar;
begin
  {$ifdef windows}
  if formsettings.cbKernelOpenProcess.Checked then
  begin
    if processid = 0 then
      exit;

    if not IsValidHandle(processhandle) then
      if messagedlg(rsTheProcessIsnTFullyOpenedIndicatingAInvalidProcess,
        mtWarning, [mbYes, mbNo], 0) <> mrYes then
        exit;

    peprocess := GetPEProcess(processid);
    ShowMessage('PEProcess=' + IntToHex(peprocess, 8));
    memorybrowser.memoryaddress := peprocess;

  end;
  {$endif}
end;

procedure TMainForm.ProcessLabelMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: integer);
begin
  {$ifdef windows}
  if assigned(newkernelhandler.IsValidHandle) then
  begin
    if (button = mbright) and (DBKLoaded) and newkernelhandler.IsValidHandle(processhandle) then
    begin
      outputdebugstring('(button = mbright) and (DBKLoaded) and IsValidHandle(processhandle)');
      tfrmProcessInfo.Create(self).Show;
    end;
  end
  else
    outputdebugstring('IsValidHandle is unassigned');
  {$endif}
end;

procedure TMainForm.cbUnrandomizerClick(Sender: TObject);
begin
  if cbunrandomizer.Checked then
  begin
    if (messagedlg(rsUnrandomizerInfo, mtWarning, [mbYes, mbNo], 0) = mrYes) then
    begin
      unrandomize := tunrandomize.Create(True);
      with unrandomize do
      begin

        progressbar := tprogressbar.Create(self);
        progressbar.AnchorSideLeft.control:=cbunrandomizer;
        progressbar.AnchorSideLeft.side:=asrLeft;

        progressbar.AnchorSideRight.control:=cbunrandomizer;
        progressbar.AnchorSideRight.side:=asrRight;

        progressbar.AnchorSideTop.control:=cbunrandomizer;
        progressbar.AnchorSideTop.side:=asrTop;

        progressbar.AnchorSideBottom.control:=cbunrandomizer;
        progressbar.AnchorSideBottom.side:=asrBottom;

        progressbar.Anchors:=[akTop, akLeft, akRight, akBottom];

        progressbar.parent := self;
        cbunrandomizer.Enabled := False;
        start;
      end;
    end
    else
      cbUnrandomizer.Checked := False;
  end
  else
  begin
    if unrandomize <> nil then
      FreeAndNil(unrandomize);
  end;
end;

procedure TMainForm.cbUnrandomizerMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: integer);
begin
  if cbunrandomizer.Checked and (button = mbright) then
  begin
    //show unrandimized addresses
    unrandomize.showaddresses;
  end;
end;


procedure TMainForm.SaveIntialTablesDir(dir: string);
var
  reg: tregistry;
begin
  reg := Tregistry.Create;
  try
    Reg.RootKey := HKEY_CURRENT_USER;
    if Reg.OpenKey('\Software\'+strCheatEngine, True) then
      reg.WriteString('Initial tables dir', dir);

  finally
    reg.Free;
  end;
end;

procedure TMainForm.actOpenExecute(Sender: TObject);
var
  merge: boolean;
  app: word;
  Extension,oldFileName: string;

begin


  merge := False;
  if not autoopen then
    if CheckIfSaved = False then
      exit;


  oldFileName:=Opendialog1.FileName;
  if autoopen or Opendialog1.Execute then
  begin
    SaveIntialTablesDir(extractfilepath(Opendialog1.filename));

    autoopen := False;
    Extension := uppercase(extractfileext(opendialog1.filename));
    if (Extension <> '.XML') and
       {(Extension<>'.PTR') and
       (Extension<>'.AMT') and
       (Extension<>'.GH') and
       (Extension<>'.CET') and
       (Extension<>'.CT2') and
       (Extension<>'.CT3') and    }
      (Extension <> '.CT') and (Extension <> '.CETRAINER') then
      raise Exception.Create(strUnknownExtension);


    if ((addresslist.Count > 0) or (advancedoptions.count > 0) or (DissectedStructs.count>0) ) and
      (Extension <> '.EXE') then
    begin
      app := messagedlg(rsDoYouWishToMergeTheCurrentTableWithThisTable,
        mtConfirmation, mbYesNoCancel, 0);
      case app of
        mrCancel: exit;
        mrYes: merge := True;
        mrNo: merge := False;
      end;

    end;

    try
      LoadTable(Opendialog1.filename, merge);
      SaveDialog1.filename:=Opendialog1.filename;
      SaveDialog1.InitialDir:=opendialog1.InitialDir;

      UserDefinedTableName:=Opendialog1.filename;
      reinterpretaddresses;

      recentFilesUpdate(Opendialog1.filename);
    except
      on e:exception do
        MessageDlg('This table failed to load: '+e.message,mtError,[mbok],0);
    end;
  end
  else Opendialog1.FileName:=oldFileName;

  if (advancedoptions <> nil) and (advancedoptions.count>0) then
    advancedoptions.Show;
end;



procedure TMainForm.actSaveExecute(Sender: TObject);
var
  protect: boolean;
  oldFileName: string;
begin
  saveGotCanceled:=true;
  protect := False;
  if (savedialog1.FileName = '') and (opendialog1.filename <> '') then
  begin
    //set the filename the table was opened with to the filename you save as default to
    //and dont forget to change the extension to .CT
    savedialog1.FileName := ChangeFileExt(opendialog1.FileName, '');
  end;


  oldFileName:=Savedialog1.FileName;
  if Savedialog1.Execute then
  begin
    if uppercase(ExtractFileExt(savedialog1.FileName)) = '.CETRAINER' then
      protect := MessageDlg(rsDoYouWantToProtectThisTrainerFileFromEditing,
        mtConfirmation, [mbYes, mbNo], 0) = mrYes;

    savetable(savedialog1.FileName, protect);

    saveGotCanceled:=false;
    opendialog1.FileName := savedialog1.filename;
    opendialog1.InitialDir:=savedialog1.InitialDir;
    SaveIntialTablesDir(extractfilepath(savedialog1.filename));

    UserDefinedTableName:=savedialog1.filename;

    recentFilesUpdate(savedialog1.filename);
  end
  else Savedialog1.FileName:=oldFileName;
end;

procedure TMainForm.actAutoAssembleExecute(Sender: TObject);
begin
  tfrmautoinject.Create(self).Show;
end;

procedure TMainForm.changeScriptCallback(memrec: TMemoryRecord; script: string; scriptchanged: boolean);
{
Gets called when a edit script is done
}
begin
  if scriptchanged then
    memrec.AutoAssemblerData.script.Text := script;

  memrec.endEdit; //release it so the user can delete it if he/she wants to
end;

function TMainForm.AddressListAutoAssemblerEdit(Sender: TObject; memrec: TMemoryRecord): boolean;
var
  x: TFrmAutoInject;
  y: array of integer;
begin
  result:=false;  //not used
  if memrec.AsyncProcessing then exit;

  if memrec.isBeingEdited then
  begin
    if memrec.autoAssembleWindow<>nil then
    begin
      if memrec.autoAssembleWindow.WindowState<>wsNormal then
        memrec.autoAssembleWindow.WindowState:=wsNormal;

      memrec.autoAssembleWindow.show;
      memrec.autoAssembleWindow.BringToFront;
    end;
  end
  else
  begin
    x := tfrmautoinject.Create(self);
    x.memrec:=memrec;
    with x do
    begin
      //name:='AAEditScript';
      new1.Enabled := False;
      miNewTab.Visible := false;

      editscript := True;
      editscript2 := True;


      memrec.beginEdit;
      memrec.autoAssembleWindow := x;
      callbackroutine := @changeScriptCallback;

      assemblescreen.Text := memrec.AutoAssemblerData.script.Text;

      setlength(y, 0);
      loadformposition(x, y);

      Caption := Format(rsAutoAssembleEdit, [memrec.Description]);
      Show;

    end;

  end;

end;

procedure TMainForm.miAsyncScriptClick(Sender: TObject);
begin
  if (addresslist.selectedRecord <> nil) and
    (addresslist.selectedRecord.VarType = vtAutoAssembler) then
     addresslist.selectedRecord.Async:=miAsyncScript.Checked;
end;


procedure TMainForm.Changescript1Click(Sender: TObject);
begin
  if (addresslist.selectedRecord <> nil) and
    (addresslist.selectedRecord.VarType = vtAutoAssembler) then
    AddressListAutoAssemblerEdit(addresslist, addresslist.selectedRecord);
end;

procedure TMainForm.Forcerechecksymbols1Click(Sender: TObject);
begin
  outputdebugstring('Forcerechecksymbols');
  symhandler.reinitialize;
  symhandler.waitforsymbolsloaded;
//  addresslist.needsToReinterpret := True;
  addresslist.reinterpretAddresses;
end;

procedure TMainForm.Edit;
var
  frmPasteTableentry: TfrmPasteTableentry;
  replace_find: string;
  replace_with: string;
  changeoffsetstring: string;
  changepointerlastoffsetstring: string;
  changeoffset: int64;
  changepointerlastoffset: int64;
  i: integer;
  hasselected: boolean;
  childrenaswell: boolean;
  relativeaswell: boolean;
  checkifrelative: boolean=true;
  s: string;
begin
  if addresslist.Count = 0 then
    exit;

  relativeaswell:=false;

  frmPasteTableentry := TfrmPasteTableentry.Create(self);
  try
    frmPasteTableentry.Caption := rsEditAddresses;
    frmPasteTableentry.Button1.Caption := rsEdit;

    if frmpastetableentry.showmodal = mrCancel then
      exit;
    replace_find := frmpastetableentry.edtFind.Text;
    replace_with := frmpastetableentry.edtReplace.Text;

    changeoffsetstring := '$' + stringreplace(frmpastetableentry.edtOffset.Text, '-', '-$', [rfReplaceAll]);
    changeoffsetstring := stringreplace(changeoffsetstring, '$-', '-', [rfReplaceAll]);
    changepointerlastoffsetstring:='$'+stringreplace(frmpastetableentry.edtPointerLastOffset.Text,'-','-$',[rfReplaceAll]);
    changepointerlastoffsetstring:=stringreplace(changepointerlastoffsetstring,'$-','-',[rfReplaceAll]);

    if not TryStrToInt64(changeoffsetstring,changeoffset) then changeoffset:=0;
    if not TryStrToInt64(changepointerlastoffsetstring,changepointerlastoffset) then changepointerlastoffset:=0;

    childrenaswell:=frmPasteTableentry.cbChildrenAsWell.checked;
  finally
    frmPasteTableentry.Free;
  end;


  hasselected := False;
  for i := 0 to addresslist.Count - 1 do
  begin
    if addresslist[i].isselected then
    begin
      hasselected := True;
      break;
    end;
  end;

  for i := 0 to addresslist.Count - 1 do
  begin
    if (hasselected and addresslist[i].isSelected) or (not hasselected) then
    begin
      if checkifrelative and (addresslist[i].interpretableaddress<>'') then
      begin
        s:=trim(addresslist[i].interpretableaddress);
        if (s<>'') and (s[1] in ['-','+']) then
        begin
          relativeaswell:=messagedlg(rsAdjustMRwithRelativeAddress, mtConfirmation, [mbyes, mbno], 0) = mryes;
          checkifrelative:=false;
        end;
      end;

      addresslist[i].adjustAddressby(changeoffset, changepointerlastoffset, childrenaswell, relativeaswell);
      addresslist[i].replaceDescription(replace_find, replace_with, childrenaswell);
    end;
  end;
end;

procedure TMainForm.Smarteditaddresses1Click(Sender: TObject);
begin
  edit;
end;


procedure TMainForm.miGeneratePointermapClick(Sender: TObject);
var
  frmPointerScanner: TfrmPointerScanner;
  oldSettingsForm: tfrmpointerscannersettings;
begin
  frmPointerScanner := tfrmpointerscanner.Create(self);
  frmPointerScanner.Show;

  oldSettingsForm:=frmpointerscannersettings;

  frmpointerscannersettings := tfrmpointerscannersettings.Create(self);

  if processhandler.is64Bit then
    frmpointerscannersettings.edtReverseStop.text:='00007FFFFFFFFFFF'
  else
  begin
    if Is64bitOS then
      frmpointerscannersettings.edtReverseStop.text:='FFFFFFFF'
    else
      frmpointerscannersettings.edtReverseStop.text:='7FFFFFFF';
  end;

  frmpointerscannersettings.CbAlligned.checked:=true;
  frmpointerscannersettings.cbConnectToNode.checked:=false;

  frmpointerscannersettings.rbGeneratePointermap.checked:=true;
  frmpointerscannersettings.btnOk.Click;

  frmPointerScanner.SkipNextScanSettings:=true;
  frmPointerScanner.Method3Fastspeedandaveragememoryusage1.Click;

  freeandnil(frmpointerscannersettings);

  frmpointerscannersettings:=oldSettingsForm;
end;

procedure TMainForm.Pointerscanforthisaddress1Click(Sender: TObject);
var
  address: ptrUint;
  Count: dword;
  j: integer;
  check: boolean;
  i: integer;
  findpointeroffsets: boolean;

  frmPointerScanner: TfrmPointerScanner;
  memrec: TMemoryRecord;
begin
  if addresslist.selectedRecord <> nil then
  begin
    memrec := addresslist.selectedRecord;
    findpointeroffsets := False;


    address := memrec.GetRealAddress;


    //default
    frmPointerScanner := tfrmpointerscanner.Create(self);
    frmPointerScanner.Show;

    if frmpointerscannersettings = nil then //used over and over
      frmpointerscannersettings := tfrmpointerscannersettings.Create(self);

    frmpointerscannersettings.cbAddress.Text := inttohex(address, 8);
    frmpointerscannersettings.cbCompareToOtherPointermaps.Checked:=false;
    frmpointerscannersettings.cbUseLoadedPointermap.checked:=false;

    if findpointeroffsets then
    begin
      //create and fill in the offset list

      frmpointerscannersettings.cbMustEndWithSpecificOffset.Checked := True;
      TOffsetEntry(frmpointerscannersettings.offsetlist[0]).offset := memrec.offsets[0].offset;

      for i := 1 to memrec.offsetcount - 1 do
      begin
        frmpointerscannersettings.btnAddOffset.Click;
        TOffsetEntry(frmpointerscannersettings.offsetlist[i]).offset := memrec.offsets[i].offset;
      end;
    end;

    frmpointerscannersettings.rbFindAddress.checked:=true;
    frmPointerScanner.Method3Fastspeedandaveragememoryusage1.Click;

  end;
end;

procedure TMainForm.OnToolsClick(Sender: TObject);
begin
  shellexecute(0, 'open', PChar(
    formsettings.lvTools.Items[TMenuItem(Sender).Tag].SubItems[0]), nil, nil, SW_SHOW);
end;

procedure TMainForm.plugintype5click(Sender: TObject);
var
  x: TPluginfunctionType5;
begin
  x := TPluginfunctionType5(tmenuitem(Sender).Tag);
  if x <> nil then
    x.callback();
end;

procedure TMainForm.plugintype0click(Sender: TObject);
var
  selectedrecord: PPlugin0_SelectedRecord;
var
  x: TPluginfunctionType0;
  interpretableaddress: string[255];
  description: string[255];
  i: integer;
  offsets: PDwordArray;

  a, b, c, d, e, f, g, h, j: dword;

  t: TVariableType;
begin
  if addresslist.selectedRecord = nil then
    exit;

  interpretableaddress := ' ';
  description := ' ';


  getmem(selectedrecord, sizeof(TPlugin0_SelectedRecord));
  //fill it with data

  interpretableaddress := addresslist.selectedRecord.interpretableaddress;

  selectedrecord^.interpretedaddress := @interpretableaddress[1];

  selectedrecord^.address := addresslist.selectedRecord.getrealAddress;
  selectedrecord^.ispointer := addresslist.selectedRecord.IsPointer;
  selectedrecord^.countoffsets := addresslist.selectedRecord.offsetCount;

  getmem(offsets, selectedrecord^.countoffsets * 4); //don't forget to free
  selectedrecord^.offsets := offsets;
  for i := 0 to selectedrecord^.countoffsets - 1 do
    pdword(selectedrecord^.offsets)[i] := addresslist.selectedRecord.offsets[i].offset;

  description := addresslist.selectedRecord.Description;
  selectedrecord^.description := @description[1];

  selectedrecord^.valuetype := integer(addresslist.selectedRecord.VarType);
  selectedrecord^.size := addresslist.selectedRecord.bytesize;



  x := TPluginfunctionType0(tmenuitem(Sender).Tag);
  if x <> nil then
  begin

    interpretableaddress[length(interpretableaddress) + 1] := #0;
    description[length(description) + 1] := #0;

    if x.callback(selectedrecord) then
    begin

      interpretableaddress[255] := #0;
      description[255] := #0;

      pbyte(@interpretableaddress[0])^ := StrLen(@interpretableaddress[1]);
      pbyte(@description[0])^ := StrLen(@description[1]);

      addresslist.selectedRecord.interpretableaddress := interpretableaddress;

      addresslist.selectedRecord.Description := description;
      byte(t) := selectedrecord^.valuetype;
      addresslist.selectedRecord.VarType := t;

      //load back and free memory
      freememandnil(offsets);
      //using my own var instead the user is lame enough to mess up the pointer
      addresslist.selectedRecord.ReinterpretAddress;
    end;
    //showmessage(inttohex(dword(@x.callback),8));
  end;


  addresslist.selectedRecord.refresh;

end;


//------------------foundlist------------------

procedure TMainForm.Foundlist3Data(Sender: TObject; Item: TListItem);
var
  extra: dword;
  Value, s, PreviousValue: string;
  Address: ptruint;
  addressString: string;
  valuetype: TVariableType;

  ssVt: TVariableType;
  p: pointer;
  invalid: boolean;
  ct: TCustomType;

  part: integer;
  error: string;

  hexadecimal: boolean;

  PreviousValueList: tstringlist=nil;
  i: integer;
begin
  //put in data
  ct:=foundlist.CustomType;

  part:=0;


  try
    valuetype:=foundlist.vartype;
    address := foundlist.GetAddress(item.Index, extra, Value);

    if (address=0) then
    begin
      item.Caption := rsProcessing;
      for i:=1 to foundlist3.ColumnCount-1 do
        item.subitems.add(rsProcessing);

      exit;
    end;

    if showStaticAsStatic then
      AddressString:=foundlist.GetModuleNamePlusOffset(item.index)
    else
      AddressString:=inttohex(address,8);


    hexadecimal:=foundlist.isHexadecimal;

    if foundlistDisplayOverride<>0 then
    begin
      if foundlistDisplayOverride=7 then
        hexadecimal:=not hexadecimal
      else
      begin
        case foundlistDisplayOverride of
          1: valuetype:=vtByte;
          2: valuetype:=vtWord;
          3: valuetype:=vtDword;
          4: valuetype:=vtQword;
          5: valuetype:=vtSingle;
          6: valuetype:=vtDouble;
        end;
        hexadecimal:=false;
      end;

      if foundlistDisplayOverride>=1000 then
      begin
        if (foundlistDisplayOverride-1000)<customTypes.count then
        begin

          if TCustomType(customTypes[foundlistDisplayOverride-1000]).bytesize<=memscan.Getbinarysize then
          begin
            valuetype:=vtCustom;
            ct:=TCustomType(customTypes[foundlistDisplayOverride-1000]);
          end;
        end;
      end;

      if valuetype=vtAll then
        value:=readAndParseAddress(address, TVariableType(extra), ct, hexadecimal)
      else
        value:=readAndParseAddress(address, valuetype, ct, hexadecimal);
    end;


    PreviousValue:=value;


    if foundlist.vartype = vtBinary then //binary
    begin
      AddressString := AddressString + '^' + IntToStr(extra);
    end
    else
    if foundlist.vartype = vtAll then //all
    begin
      if extra >= $1000 then
      begin
        ct:=TCustomType(customTypes[extra - $1000]);
        valuetype:=vtCustom;
        AddressString := AddressString + ':' + ct.Name;
      end
      else
      begin
        valuetype := TVariableType(extra);

        //here valuetype is stored using the new method
        case valuetype of
          vtByte: AddressString := AddressString + ':1';
          vtWord: AddressString := AddressString + ':2';
          vtDword: AddressString := AddressString + ':4';
          vtQword: AddressString := AddressString + ':8';
          vtSingle: AddressString := AddressString + ':s';
          vtDouble: AddressString := AddressString + ':d';
        end;
      end;
    end;

    if miShowPreviousValue.checked and (previousresultlist<>nil) then
    begin
      PreviousValue:='';
      PreviousValueList:=tstringlist.create;
      //get the previous value of this entry
      invalid:=false;
      case foundlist.vartype of
        vtByte: ssVt:=vtbyte;
        vtWord: ssVt:=vtword;
        vtDword: ssVt:=vtdword;
        vtSingle: ssVt:=vtsingle;
        vtDouble: ssVt:=vtdouble;
        vtQword: ssVt:=vtQword;
        vtCustom: ssVt:=vtCustom;
        vtAll: ssVt:=vtall;
        else
          invalid:=true;

      end;

      if not invalid then
      begin

        for i:=0 to PreviousResultList.count-1 do
        begin
          if foundlist3.columns[i+2].Visible then
          begin
            //p:=PreviousResultList[i].getpointertoaddress(address, ssvt, ct);

            if TSavedScanHandler(PreviousResultList[i]).getStringFromAddress(address, s,hexadecimal,foundlist.isSigned, valuetype, ct)=false then //valuetype and CT are only used if the memscan was a vtAll type
            begin
              if TSavedScanHandler(PreviousResultList[i]).lastFail=1 then
                s:=rsPleaseWait
              else
                s:=rsBusy+' : '+inttostr(TSavedScanHandler(PreviousResultList[i]).lastFail);
            end;
          end
          else
            s:='';

          previousvaluelist.add(s);

          {$ifdef darwin}
          if i+2=fActivePreviousResultColumn then
            PreviousValue:=s;
          {$endif}
        end;
      end;
    end;


    part:=3; //meh

    {$ifdef darwin}
    //no ownerdraw support for macos listview
    if (previousvalue<>rsPleaseWait) and (value<>previousvalue) then
      value:='* '+value+' *';
    {$endif}


    item.Caption := AddressString;
    item.subitems.add(Value);
    if previousvaluelist<>nil then
    begin
      for i:=0 to previousvaluelist.count-1 do
        item.subitems.add(previousvaluelist[i]);
    end;




  except
    on e: exception do
    begin
    //ShowMessage(IntToStr(item.index));

      error:=rsCEError+inttostr(item.index)+rsPart+inttostr(part)+':'+e.message;

      if part in [0,3] then
      begin
        item.Caption:=error;
        item.subitems.add(e.Message);
        item.subitems.add('');
      end;

      if part=1 then
      begin
        item.Caption := AddressString;
        item.subitems.add(error);
        item.subitems.add(e.Message);
      end;

      if part=2 then
      begin
        item.Caption := AddressString;
        item.subitems.add(Value);
        item.subitems.add(error);
      end;

      if PreviousResultList<>nil then
        for i:=1 to PreviousResultList.count-1 do
          item.subitems.add('');
    end;
  end;

  if previousvaluelist<>nil then
    freeandnil(previousvaluelist);
end;

procedure TMainForm.UpdateFoundlisttimerTimer(Sender: TObject);
begin

  if foundlist <> nil then
    foundlist.RefetchValueList;
end;

procedure TMainForm.Foundlist3KeyDown(Sender: TObject; var Key: word;
  Shift: TShiftState);
var
  i: integer;
begin

  foundlistpopupPopup(sender);
  if ((key = Ord('A')) and (ssctrl in Shift) and not (ssalt in Shift)) then
  begin
    //select all
    if foundlist3.Items.Count < 5000 then
    begin
      for i := 0 to foundlist3.items.Count - 1 do
        foundlist3.Items[i].Selected := True;

      //      foundlist3.SelectAll;
    end;
  end;
end;


procedure TMainForm.miTutorialClick(Sender: TObject);
begin
  if not fileexists(cheatenginedir+{$ifdef altname}'rtmtutorial-i386.exe'{$else}'Tutorial-i386.exe'{$endif}) then
  begin
    if fileexists(cheatenginedir+{$ifdef altname}'rtmtutorial-i386.cepack'{$else}'Tutorial-i386.cepack'{$endif}) then
      ceunpackfile(cheatenginedir+{$ifdef altname}'rtmtutorial-i386.cepack'{$else}'Tutorial-i386.cepack'{$endif}, cheatenginedir+{$ifdef altname}'rtmtutorial-i386.exe'{$else}'Tutorial-i386.exe'{$endif}, false);
  end;

  shellexecute(0, 'open', pchar(cheatenginedir+{$ifdef altname}'rtmtutorial-i386.exe'{$else}'Tutorial-i386.exe'{$endif}), nil, nil, sw_show);
end;

procedure TMainForm.miFlFindWhatAccessesClick(Sender: TObject);
var
  address: ptrUint;
  res: word;
begin
  if foundlist3.Selected<>nil then
  begin
    address:=foundlist.GetAddress(foundlist3.Selected.Index);
    if (not startdebuggerifneeded) then
      exit;

    DebuggerThread.FindWhatAccesses(address, memscan.Getbinarysize div 8);
  end;
end;

procedure TMainForm.miFlFindWhatWritesClick(Sender: TObject);
var
  address: ptrUint;
  extra: dword;
  res: word;
begin
  if foundlist3.Selected<>nil then
  begin
    address:=foundlist.GetAddress(foundlist3.Selected.Index);
    if (not startdebuggerifneeded) then
      exit;

    DebuggerThread.FindWhatWrites(address, memscan.Getbinarysize div 8);
  end;

end;

procedure TMainForm.miSaveFileClick(Sender: TObject);
begin
  {$ifdef windows}
  if Processwindow = nil then
    ProcessWindow := TProcessWindow.Create(application);

  if ProcessWindow.opendialog2.Execute then
    Filehandler.CommitChanges(ProcessWindow.opendialog2.filename);
  {$endif}
end;

procedure TMainForm.miChangeValueBackClick(Sender: TObject);
var
  _currentlySelectedSavedResultname: string;
  s: tstringlist;
  i: integer;
  a: ptruint;
  p: pointer;

  bytesize: integer;
  x: ptruint;

  savedscan: TSavedScanHandler;
begin
  //show a list of possible options. Previous, last scan, savedscan
  if memscan=nil then exit;
  if PreviousResultList.count=0 then exit;
  if GetVarType in [vtBinary, vtByteArray, vtAll, vtGrouped] then exit;

  bytesize:=memscan.Getbinarysize div 8;
  if bytesize=0 then exit;

  s:=tstringlist.create();

  memscan.getsavedresults(s);
  s.insert(0,'Last Scan');

  i:=ShowSelectionList(self, rsPreviousValueList, rsSelectTheSavedResult, s, currentlySelectedSavedResultname);
  s.free;
  if i=-1 then exit;
  if i=0 then currentlySelectedSavedResultname:='TMP';

  savedscan:=TSavedScanHandler.create(memscan.getScanFolder, currentlySelectedSavedResultname);
  savedscan.memscan:=memscan;
  savedscan.AllowNotFound:=true;
  savedscan.AllowRandomAccess:=true;

  try
    {$ifdef darwin}
    a:=foundlist.GetAddress(foundlist3.Selected.Index);
    p:=savedscan.getpointertoaddress(a, memscan.VarType,memscan.CustomType);

    if p<>nil then
      WriteProcessMemory(processhandle, pointer(a),p,bytesize,x);

    {$endif}

    for i:=0 to foundlist3.items.Count-1 do
    begin
      if foundlist3.Items[i].Selected then
      begin
        a:=foundlist.GetAddress(i);
        p:=savedscan.getpointertoaddress(a, memscan.VarType,memscan.CustomType);

        if p<>nil then
          WriteProcessMemory(processhandle, pointer(a),p,bytesize,x);
      end;
    end;
  finally
    savedscan.free;
  end;
end;



procedure TMainForm.miChangeValueClick(Sender: TObject);
var
  a:ptruint;
  extra: dword;
  value, newvalue: string;
  i: integer;
  vt: TVariableType;
  customtype: TCustomType;
begin
  customtype:=nil;
  if foundlist3.Selected<>nil then
  begin
    foundlist.GetAddress(foundlist3.Selected.Index, extra, Value);

    if InputQuery(rsChangeValue, rsGiveTheNewValueForTheSelectedAddressEs, value) then
    begin
      newvalue:=value;

      if foundlist.vartype=vtAll then  //all, extra contains the vartype
      begin
        if extra<$1000 then
        begin
          vt:=TVariableType(extra);
        end
        else
        begin //custom type
          vt:=vtCustom;
          customtype:=tcustomtype(customTypes[extra-$1000]);
        end;
      end
      else
      begin
        vt:=foundlist.vartype;
        if vt=vtCustom then
          customtype:=foundlist.CustomType;
      end;

      if (vt=vtString) and (cbUnicode.checked) then
        vt:=vtUnicodeString;

      for i:=0 to foundlist3.items.Count-1 do
      begin
        if foundlist3.Items[i].Selected then
        begin
          a:=foundlist.GetAddress(i, extra, Value);

          ParseStringAndWriteToAddress(newvalue, a, vt, foundlist.isHexadecimal, customtype);
        end;

      end;

    end;

  end;


end;

var
  _us: string;



var
  advapi: thandle;
  tu: unicodestring;



procedure TMainForm.d3dclicktest(_overlayid: integer; x, y: integer);
var
  w, h: integer;
begin
  {$ifdef windows}
  w := d3dhook.getwidth;
  h := d3dhook.getheight;

  ShowMessage(rsOverlay + IntToStr(_overlayid) + rsWasClickedAtPositon +
    IntToStr(x) + ',' + IntToStr(y) + rsWidth + IntToStr(w) + rsHeight + IntToStr(h));
  {$endif}
end;





procedure TMainForm.Browsethismemoryregioninthedisassembler1Click(Sender: TObject);
var
  a, b: dword;
  s: string;
begin
  if (foundlist3.ItemIndex <> -1) then
  begin
    memorybrowser.disassemblerview.SelectedAddress :=
      foundlist.GetAddress(foundlist3.ItemIndex, b, s);
    memorybrowser.Show;
  end;
end;

procedure TAutoAttachThread.autoattachcheck;
begin
  MainForm.autoattachcheck(CurrentProcessList);
end;

constructor TAutoAttachThread.Create(CreateSuspended: boolean);
begin
  Interval:=2000;
  CurrentProcessList:=TStringList.Create;
  inherited Create(CreateSuspended);
end;

procedure TAutoAttachThread.Execute;
begin
  while not terminated do
  begin
    if ((MainForm.autoattachlist = nil) or (formsettings = nil) or (MainForm.extraautoattachlist = nil)) or
       ((MainForm.autoattachlist.Count+MainForm.extraautoattachlist.Count)<1) or
       ((not formsettings.cbAlwaysAutoAttach.Checked) and ((processhandle <> 0) or (processid <> 0))) then
    begin
      sleep(Interval);
      continue;
    end;

    getprocesslist(CurrentProcessList,false,true);
    synchronize(@autoattachcheck);
    sleep(Interval);
  end;
end;

procedure TMainForm.autoattachcheck(pl: TStringList = nil);
var
  i, j, k: integer;
  newPID: dword;
  a: string;
  p: string;

  oldpid: dword;
  oldphandle: thandle;
  attachlist: TStringList;
begin
  attachlist := TStringList.Create;
  try
    attachlist.AddStrings(autoattachlist);
    attachlist.AddStrings(extraautoattachlist);


    if attachlist.Count > 0 then
    begin
      //in case there is no processwatcher this timer will be used to enumerate the processlist every 2 seconds
      if pl=nil then
      begin
        pl := TStringList.Create;
        getprocesslist(pl,false,true);
      end;

      try
        for i := 0 to attachlist.Count - 1 do
        begin
          a := uppercase(trim(attachlist.Strings[i]));
          for j := pl.Count - 1 downto 0 do //can't do indexof
          begin

            p := uppercase(pl.strings[j]);
            if pos(a, p) = 10 then
            begin
              //the process is found
              p := '$' + copy(p, 1, 8);
              val(p, newPID, k);
              if k = 0 then
              begin
                if ProcessHandler.processid = newPID then
                  exit; //already attached to the newest one

                if newPID=GetCurrentProcessId then
                  continue; //Do not autoattach to self

                openprocessPrologue;

                oldpid := ProcessHandler.processid;
                oldphandle := processhandler.processhandle;

                ProcessHandler.processid := newPID;
                unpause;
                DetachIfPossible;



                MainForm.ProcessLabel.Caption := pl.strings[j];
                Open_Process;
                enablegui(False);

                openProcessEpilogue('', oldpid, oldphandle, True);

                symhandler.reinitialize;
                reinterpretaddresses;
                exit;
              end;
            end;
          end;

        end;
        //  pl.IndexOf(autoattachlist.items[i]);

      finally
        cleanProcessList(pl);
      end;

    end;


  finally
    attachlist.Free;
  end;
end;

procedure TMainForm.AutoAttachTimerTimer(Sender: TObject);
begin
  if (autoattachlist = nil) or (formsettings = nil) or (extraautoattachlist = nil) then
    exit;

  if (not formsettings.cbAlwaysAutoAttach.Checked) and
    ((processhandle <> 0) or (processid <> 0)) then
    exit;

  autoattachcheck;
end;



procedure TMainForm.btnFirstClick(Sender: TObject);
var
  svalue2: string;
  percentage: boolean;
  fastscanmethod: TFastscanmethod;
begin
  {$ifdef windows}
  if aprilfools then decreaseCheatECoinCount;

  QueryPerformanceCounter(scantimestart);
  {$endif}


  cleanupPreviousResults;

  if (memscan=nil) or (foundlist=nil) then raise exception.create(rsUnableToScanFixYourScanSettings);

  foundlist.Deinitialize; //unlock file handles



  if cbpercentage <> nil then
    percentage := cbpercentage.Checked
  else
    percentage := False;


  if btnFirst.tag = 0 then
  begin


    ProgressBar.min := 0;
    ProgressBar.max := 1000;
    ProgressBar.position := 0;

    if scanvalue2 <> nil then
      svalue2 := scanvalue2.Text
    else
      svalue2 := '';

    lastscantype := scantype.ItemIndex;

    if cbPauseWhileScanning.Checked then
    begin
      advancedoptions.Pausebutton.down := True;
      advancedoptions.Pausebutton.Click;
    end;

    case cbWritable.State of
      cbUnchecked: memscan.scanWritable := scanExclude;
      cbChecked: memscan.scanWritable := scanInclude;
      cbGrayed: memscan.scanWritable := scanDontCare;
    end;

    case cbExecutable.State of
      cbUnchecked: memscan.scanExecutable := scanExclude;
      cbChecked: memscan.scanExecutable := scanInclude;
      cbGrayed: memscan.scanExecutable := scanDontCare;
    end;

    case cbCopyOnWrite.State of
      cbUnchecked: memscan.scanCopyOnWrite := scanExclude;
      cbChecked: memscan.scanCopyOnWrite := scanInclude;
      cbGrayed: memscan.scanCopyOnWrite := scanDontCare;
    end;

    {$ifdef darwin}
    case cbDirty.state of
      cbUnchecked: memscan.scanDirty := scanExclude;
      cbChecked: memscan.scanDirty := scanInclude;
      cbGrayed: memscan.scanDirty := scanDontCare;
    end;
    {$endif}

    if cbfastscan.Checked then
    begin
      if rbFsmAligned.Checked then
        fastscanmethod := fsmAligned
      else
        fastscanmethod := fsmLastDigits;
    end
    else
      fastscanmethod := fsmNotAligned;

    memscan.floatscanWithoutExponents:=cbFloatSimple.checked;
    memscan.inversescan:=cbNot.Checked and cbnot.Visible;

    memscan.codePage:=cbCodePage.checked;
    if ScanTabList <> nil then
      ScanTabList.Enabled := False;

    memscan.luaformula:=cbLuaFormula.visible and cbLuaFormula.checked;
    memscan.NewLuaState:=cbNewLuaState.Checked;
    memscan.busyformIsModal:=true;
    memscan.workingsetonly:=(getConnection=nil) and cbPresentMemoryOnly.checked;  //workingsetonly is false when networked

    memscan.firstscan(GetScanType2, getVarType2, roundingtype,
      scanvalue.Text, svalue2, scanStart, scanStop,
      cbHexadecimal.Checked, rbdec.Checked, cbunicode.Checked, cbCaseSensitive.Checked, fastscanmethod, edtAlignment.Text,
      TCustomType(vartype.items.objects[vartype.ItemIndex]));

    DisableGui;

    SpawnCancelButton;

  end
  else if btnFirst.tag = 2 then
  begin
    //btnNewScan
    btnFirst.Tag := 0;
    donewscan;
    memscan.newscan; //cleanup memory and terminate all background threads
  end;
end;

procedure TMainForm.MemScanStart(sender: TObject);
begin
  foundlist.Deinitialize; //unlock file handles
  cleanupPreviousResults;
end;

procedure TMainForm.MemScanDone(sender: TObject);
var
  i: integer;
  _canceled: boolean;
  actuallyshown: double;
  error: boolean;
  _previous: string;

  c: qword;

  scantime: qword;
begin
  {$ifdef windows}
  QueryPerformanceCounter(scantimefinish);

  scantime:=scantimefinish-scantimestart;

  {$ifdef SCANPERF}
  if ssCtrl in GetKeyShiftState then
    showmessage(inttostr(scantime));
  {$endif}
  {$endif}


  if ScanTabList <> nil then
    ScanTabList.Enabled := True;

  i := 0;
  _canceled := False;

  btnFirst.Tag := 2;
  btnFirst.Caption := rsScan;
  btnNext.tag := 0;
  ProgressBar.Position := 0;

  error:=tmemscan(sender).hasError;

  if tmemscan(sender).hasError then
  begin
    error:=true;
    messagedlg(Format(rsScanError, [memscan.GetErrorString]), mtError, [mbOK], 0);
  end
  else
    error:=false;


  enablegui(memscan.LastScanType = stNextScan);
  destroyCancelButton;



  foundlist.Initialize(getvartype, memscan.Getbinarysize, cbHexadecimal.Checked,
    formsettings.cbShowAsSigned.Checked, not rbBit.Checked, cbunicode.Checked,
    TCustomType(VarType.items.objects[vartype.ItemIndex]));

  c:=memscan.GetFoundCount;
  foundcount := c;

  cleanupPreviousResults;

  if not compareToSavedScan then
    _previous:='TMP'
  else
    _previous:=currentlySelectedSavedResultname;

  reloadPreviousResults;
  for i:=0 to PreviousResultList.count-1 do
    if TSavedScanHandler(PreviousResultList[i]).name=_previous then
      ActivePreviousResultColumn:=i+2;

  if (foundlist3.items.Count <> foundcount) and (not foundlist.isUnknownInitialValue) then
  begin
    actuallyshown := foundlist3.items.Count;
    foundcountlabel.Caption := foundcountlabel.Caption + ' (' + rsShown +
      ': ' + Format('%.0n', [actuallyshown]) + ')';
  end;

  if memscan.lastscantype = stFirstScan then
  begin
    //firstscan Epilogue
    setGbScanOptionsEnabled(False);

    vartype.Enabled := False;
    btnNextScan.Enabled := True;
    btnNewScan.Caption := strNewScan;
  end;


  ProgressBar.Position := 0;
  UpdateFoundlisttimer.Enabled := True;

  Scantype.ItemIndex := lastscantype;
  UpdateScanType;

  if cbpercentage <> nil then
    cbPercentageOnChange(cbpercentage);


  scanepilogue(_canceled);

  if error and (memscan.lastscantype = stFirstScan) then //firstscan failed
    btnNewScan.Click;

  if (GetScanType=soUnchanged) and cbRepeatUntilStopped.visible and cbRepeatUntilStopped.checked then
  begin
    if repeatDelay<>0 then
    begin
      if repeatScanTimer<>nil then
        freeandnil(repeatscantimer);

      repeatScanTimer:=TTimer.create(self);
      repeatscantimer.interval:=repeatdelay;
      repeatscantimer.OnTimer:=@repeatScanTimerTimer;


    end
    else
      btnNext.Click;
  end
  else
    beep; //let the blind user know the scan has finished (See, I'm thinking about the visually impeared users...)

end;

procedure TMainForm.repeatScanTimerTimer(sender: TObject);
begin
  freeandnil(repeatscantimer);
  if cbRepeatUntilStopped.visible and cbRepeatUntilStopped.checked and (GetScanType=soUnchanged) then
    btnNext.click;
end;

procedure TMainForm.CancelbuttonClick(Sender: TObject);
begin
  if cancelbutton.tag = 0 then
  begin
    cancelbutton.Caption := rsTerminatingScan;
    cancelbutton.Enabled := False;
    cancelbutton.Tag := 1; //force termination
    cancelbutton.Hint := rsThisButtonWillForceCancelAScanExpectMemoryLeaks;
    cancelbutton.ParentShowHint := False;
    cancelbutton.ShowHint := True;
    memscan.terminatescan(False);

    cancelbuttonenabler.Enabled := False;
    cancelbuttonenabler.interval := 8000; //8 seconds
    cancelbuttonenabler.tag := 1;
    cancelbuttonenabler.Enabled := True;
  end
  else
  begin
    //force it. It took too long
    memscan.TerminateScan(True);
  end;
end;

procedure TMainForm.CancelbuttonenablerInterval(Sender: TObject);
begin
  if cancelbutton <> nil then
    cancelbutton.Enabled := True;

  if cancelbutton.Tag = 1 then
    cancelbutton.Caption := rsForceTermination;
  TTimer(Sender).Enabled := False;
end;


procedure TMainForm.btnNextClick(Sender: TObject);
var
  svalue2: string;
  estimateddiskspaceneeded: qword;
  diskspacefree, totaldiskspace: int64;
  {$ifdef windows}
  totaldiskspacefree: LARGE_INTEGER;{$endif}
  percentage: boolean;
begin
  {$ifdef windows}
  if aprilfools then decreaseCheatECoinCount;
  {$endif}

  { estimateddiskspaceneeded:=foundcount*8*3;
  GetDiskFreeSpaceEx(pchar(memscan.ScanresultFolder), diskspacefree, totaldiskspace,@totaldiskspacefree);


  if estimateddiskspaceneeded>diskspacefree then
    if MessageDlg(rsYouAreLowOnDiskspaceOnTheFolderWhereTheScanresults, mtwarning, [mbyes, mbno], 0)<>mryes then exit;
     }



  if cbpercentage <> nil then
    percentage := cbPercentage.Checked
  else
    percentage := False;



  if cbPauseWhileScanning.Checked then
  begin
    advancedoptions.Pausebutton.down := True;
    advancedoptions.Pausebutton.Click;
  end;

  ProgressBar.min := 0;
  ProgressBar.max := 1000;
  ProgressBar.position := 0;


  if scanvalue2 <> nil then
    svalue2 := scanvalue2.Text
  else
    svalue2 := '';

  lastscantype := scantype.ItemIndex;

  memscan.floatscanWithoutExponents:=cbFloatSimple.checked;
  memscan.inverseScan:=cbNot.Checked and cbnot.Visible;
  memscan.codePage:=cbCodePage.checked;
  memscan.luaformula:=cbLuaFormula.visible and cbLuaFormula.checked;
  memscan.NewLuaState:=cbNewLuaState.checked;

  memscan.busyformIsModal:=not ((GetScanType=soUnchanged) and cbRepeatUntilStopped.checked);


  if ScanTabList <> nil then
    ScanTabList.Enabled := False;

  memscan.nextscan(GetScanType2, roundingtype, scanvalue.Text,
    svalue2, cbHexadecimal.Checked, rbdec.Checked,
    cbunicode.Checked, cbCaseSensitive.Checked, percentage, compareToSavedScan,
    currentlySelectedSavedResultname);
  DisableGui;
  SpawnCancelButton;
end;

procedure TMainForm.scanEpilogue(canceled: boolean);
var
  vtype: TVariableType;
  i: integer;
  bytes: tbytes;
begin

  vtype := getvartype;
  if not canceled then
  begin
    case vtype of
      vtBinary: i := memscan.getbinarysize;
      vtString: i := length(scanvalue.Text);
      vtByteArray: //array of byte
      begin
        setlength(bytes, 0);
        try
          ConvertStringToBytes(scanvalue.Text, cbHexadecimal.Checked, bytes);
          i := length(bytes);
        except
          i := 1;
        end;
        setlength(bytes, 0);
      end;
    end;
    foundlist.Initialize(vtype, i, cbHexadecimal.Checked,
      formsettings.cbShowAsSigned.Checked, not rbBit.Checked, cbunicode.Checked,
      memscan.CustomType);
  end
  else
    foundlist.Initialize(vtype, memscan.CustomType);
  //failed scan, just reopen the addressfile





  try
    if cbRepeatUntilStopped.checked=false then //don't focus. it takes way the click handlers which is needed for checkboxes
    begin

      if scanvalue.Visible and scanvalue.Enabled then
      begin
        scanvalue.SetFocus;
        scanvalue.SelectAll;
      end
      else
      if not canceled then
      begin
        btnNextScan.SetFocus;
      end;

    end;
  except

  end;



  if cbPauseWhileScanning.Checked then
  begin
    advancedoptions.Pausebutton.down := False; //resume
    advancedoptions.Pausebutton.Click;
  end;

end;


procedure TMainForm.FormDestroy(Sender: TObject);
var
  i: integer;
  oldscanstate: PScanState;
  x: array of integer;
  reg: tregistry;
begin


  if flashprocessbutton<>nil then
  begin
    flashprocessbutton.Terminate;
    flashprocessbutton.WaitFor;
    flashprocessbutton.Free;
  end;

  if freezethread<>nil then
  begin
    freezeThread.Terminate;
    freezeThread.WaitFor;
    freeandnil(freezeThread);
  end;

  setlength(x,7);
  x[0]:=addresslist.headers.Sections[0].Width;
  x[1]:=addresslist.headers.Sections[1].Width;
  x[2]:=addresslist.headers.Sections[2].Width;
  x[3]:=addresslist.headers.Sections[3].Width;
  x[4]:=addresslist.headers.Sections[4].Width;
  x[5]:=panel5.Height;
  x[6]:=foundlist3.columns[0].Width;

  saveformposition(self, x);

  if foundlist <> nil then
    foundlist.Deinitialize;

  if addresslist <> nil then
    FreeAndNil(addresslist);

  if scantablist = nil then
    if memscan <> nil then
      FreeAndNil(memscan);

  if scantablist <> nil then
  begin
    for i := 0 to scantablist.Count - 1 do
    begin
      if scantablist.SelectedTab <> i then
      begin
        oldscanstate := scantablist.TabData[i];
        freeandnil(oldscanstate^.foundlist);
        freeandnil(oldscanstate^.memscan);
        freememandnil(oldscanstate);
      end;
    end;
    FreeAndNil(scantablist);
  end;




end;

procedure TMainForm.tbSpeedChange(Sender: TObject);
var
  x: integer;
  y: single;
begin
  x := tbSpeed.position;
  case x of
    0: y := 0;
    1: y := 0.25;
    2: y := 0.5;
    3: y := 1;
    4: y := 2;
    5: y := 5;
    6: y := 10;
    7: y := 20;
    8: y := 50;
    9: y := 100;
    10: y := 200;
    11: y := 500;
    else
      y := 1;
  end;

  if x>=3 then
    editSH2.Text := format('%.0f', [y])
  else
  if x>=2 then
    editSH2.Text := format('%.1f', [y])
  else
  if x<2 then
    editSH2.Text := format('%.2f', [y]);
end;

procedure TMainForm.btnSetSpeedhack2Click(Sender: TObject);
var
  newspeed: single;
  fs: Tformatsettings;
  error: boolean;
begin
  error := False;
  try
    newspeed := StrToFloat(editsh2.Text);
  except
    fs := DefaultFormatSettings;
    try
      newspeed := StrToFloat(editsh2.Text, fs);
    except
      error := True;
    end;
  end;

  if error or IsInfinite(newspeed) or IsNan(newspeed) then
    raise Exception.Create(Format(rsIsNotAValidSpeed, [editSH2.Text]));

  if speedHack <> nil then
  begin
    {$ifdef windows}
    if speedhack.processid<>processid then
    begin
      //the process switched
      FreeAndNil(speedhack);  //recreate
      speedhack := TSpeedhack.Create;
    end;
    {$endif}

    speedhack.setSpeed(newspeed);
  end;
end;

procedure TMainForm.cbSpeedhackChange(Sender: TObject);
var ss: TShiftState;
begin
  if cbSpeedhack.Checked then
  begin
    try
      if speedhack <> nil then
        FreeAndNil(speedhack);

      speedhack := TSpeedhack.Create;
    except
      on e: Exception do
      begin
       { outputdebugstring('Normal speedhack activation failed. Checking for :"activateAlternateSpeedhack"');
        lua_getglobal(luavm, 'activateAlternateSpeedhack');//failure. check if there is an alternative in lua
        if lua_isfunction(luavm,-1) then
        begin
          OutputDebugString('Calling activateAlternateSpeedhack');
          lua_pushboolean(luavm,true);
          lua_pcall(luavm, 1,1,0);
          if lua_toboolean(luavm,-1)<>true then
            cbSpeedhack.Checked:=false;

          exit;
        end
        else
          lua_pop(luavm,1);
           }

        cbSpeedhack.Checked := False;
        MessageDlg(e.message,mtError,[mbok],0);
      end;
    end;
  end
  else
  begin
    if speedhack <> nil then
      FreeAndNil(speedhack);
  end;

  panel14.Visible := cbSpeedhack.Checked;
end;

{--------Processlist menuitem--------}
//var
//  il: TImageList;


procedure TMainForm.Process1Click(Sender: TObject);

var
  sl: TStringList;
  mi: array of TMenuItem;
  currentmi: TMenuItemExtra;
  i, j: integer;

  tempicon: Graphics.TIcon;
  tempp: tpicture;
  p: integer;

begin
  //fill with processlist
 // if il = nil then
 //   il := TImageList.Create(self);

 // il.clear;


  sl := TStringList.Create;

  try
    GetProcessList(sl);
    for i := process1.Count - 1 downto 3 do
      process1.Items[i].Free;

    setlength(mi, sl.Count);
    for i := 0 to sl.Count - 1 do
    begin
      j := sl.Count - 1 - i;
      currentmi := TMenuItemExtra.Create(self);
      currentmi.Caption := sl[i];
      {$ifdef windows}
      currentmi.Default := dword(ptrUint(PProcessListInfo(sl.Objects[i])^.processid)) = ProcessID;
      currentmi.Data := pointer(ptrUint(PProcessListInfo(sl.Objects[i])^.processid));
      {$else}
      if TryStrToInt('$'+copy(sl[i],1,pos('-',sl[i])), p) then
      begin
        currentmi.Data := pointer(p);
        currentmi.default:=p=processid;
      end;
      {$endif}

      currentmi.OnClick := @ProcessItemClick;


      {$IFDEF WINDOWS}
      if PProcessListInfo(sl.Objects[i])^.processIcon > 0 then
      begin
        tempicon := Graphics.TIcon.Create;
        tempicon.handle := PProcessListInfo(sl.Objects[i])^.processIcon;

        tempp:=TPicture.create;
        tempp.Icon:=tempicon;
        currentmi.Bitmap:=tempp.bitmap;

        tempp.free;
        tempicon.free;
      end
      else
      {$ENDIF}
        currentmi.ImageIndex := -1;

      mi[j] := currentmi;
      process1.Add(currentmi);
    end;

  finally
    cleanProcessList(sl);
    sl.Free;
  end;




end;

procedure TMainForm.ProcessItemClick(Sender: TObject);
var
  pid: dword;
  oldprocess: Dword;
  oldprocesshandle: thandle;
  oldprocessname: string;
begin

  if openprocessPrologue then
  begin
    oldprocessname := copy(mainform.ProcessLabel.Caption, pos(
      '-', mainform.ProcessLabel.Caption) + 1, length(mainform.ProcessLabel.Caption));
    oldprocess := processID;
    oldprocesshandle := processhandle;
    if (Sender is TMenuItemExtra) then
    begin
      pid := dword(ptrUint(TMenuItemExtra(Sender).Data));
      //the menuitem .data field contains the processid (and not some allocated memory)

      unpause;
      DetachIfPossible;

      with TProcessWindow.Create(self) do
      begin
        pwop(inttohex(pid, 8));
        ProcessLabel.Caption := TMenuItemExtra(Sender).Caption;
        Free;
      end;

      openprocessepilogue(oldprocessname, oldprocess, oldprocesshandle);

    end;
  end;
end;


{^^^^^^^^Processlist menuitem^^^^^^^^}
procedure TMainForm.miAboutClick(Sender: TObject);
begin
  About := TAbout.Create(self);
  About.showmodal;
end;

procedure TMainForm.CreateProcess1Click(Sender: TObject);
var
  x: dword;
  oldprocess: Dword;
  oldprocesshandle: thandle;
  oldprocessname: string;
begin
  if openprocessPrologue then
  begin

    oldprocessname := copy(mainform.ProcessLabel.Caption, pos(
      '-', mainform.ProcessLabel.Caption) + 1, length(mainform.ProcessLabel.Caption));
    oldprocess := processID;
    oldprocesshandle := processhandle;
    with TProcessWindow.Create(self) do
    begin
      miCreateProcess.Click;
      Free;
    end;

    if processid <> oldprocess then
      openprocessepilogue(oldprocessname, oldprocess, oldprocesshandle);

  end;
end;

procedure TMainForm.Helpindex1Click(Sender: TObject);
begin
  ShellExecute(0,'open','https://wiki.cheatengine.org/index.php',nil,nil,SW_SHOW);
//  Application.HelpContext(1);
end;

procedure TMainForm.New1Click(Sender: TObject);
begin
  if MessageDlg(rsAreYouSureYouWantToEraseTheDataInTheCurrentTable,
    mtConfirmation, [mbYes, mbNo], 0) = mrYes then
    clearlist;
end;

procedure TMainForm.ClearList;
{
Will remove all entries from the cheattable, comments, and advanced options window
}
begin
  Comments.Memo1.Clear;
  comments.Memo1.Lines.Add(strInfoAboutTable);
  advancedoptions.clear;
  addresslist.Clear;
end;

procedure TMainForm.ClearRecentFiles(Sender:TObject);
begin
  if MessageDlg(rsAreYouSure, mtConfirmation, [mbYes, mbNo], 0) = mrYes then
  begin
    recentfiles.Clear;
    cereg.writeStrings('Recent Files', recentfiles);
  end;
end;

procedure TMainForm.RecentFilesClick(Sender:TObject);
var filename: string;
begin
  if CheckIfSaved then
  begin
    filename:=RecentFiles[tmenuitem(sender).Tag];
    LoadTable(filename,false);
    SaveDialog1.FileName:=filename;
    OpenDialog1.FileName:=filename;
    recentFilesUpdate(filename);
  end;
end;

procedure TMainForm.File1Click(Sender: TObject);
var
  i: integer;
  m: TMenuItem;
begin
  miSaveScanresults.Enabled := memscan.nextscanCount > 0;
  miLoadRecent.Visible:=RecentFiles.Count>0;

  miLoadRecent.Clear;
  for i:=0 to RecentFiles.count-1 do
  begin
    m:=tmenuitem.Create(miLoadRecent);
    m.Caption:=RecentFiles[i];
    m.OnClick:=@RecentFilesClick;
    m.tag:=i;

    miLoadRecent.Add(m);
  end;

  m:=tmenuitem.Create(miLoadRecent);
  m.Caption:='-';
  miLoadRecent.Add(m);

  m:=tmenuitem.Create(miLoadRecent);
  m.Name:='miEmptyRecentFilesList';
  m.Caption:=rsClearRecentFiles;
  m.OnClick:=@ClearRecentFiles;
  miLoadRecent.Add(m);


  miDeleteSavedScanResults.visible:=memscan.SavedScanCount>0;
end;

procedure TMainForm.actOpenProcesslistExecute(Sender: TObject);
begin
  sbOpenProcess.Click;
end;

procedure TMainForm.Type1Click(Sender: TObject);
begin
  addresslist.doTypeChange;
end;

procedure TMainForm.DoGroupconfigButtonClick(sender: tobject);
var gcf: TfrmGroupScanAlgoritmGenerator;
begin
  gcf:=TfrmGroupScanAlgoritmGenerator.create(self);
  try
    gcf.parseParameters(scanvalue.text);
  except
    on e:exception do
    begin
      MessageDlg(e.message,mtError,[mbok],0);
      exit;
    end;
  end;

  if gcf.showmodal=mrok then
    scanvalue.text:=gcf.getparameters;

  gcf.free;
end;


function TMainForm.GetScanType2: TScanOption;
{
not needed anymore
}
begin
  result:=GetScanType;
end;

function TMainForm.GetScanType: TScanOption;
begin
  result:=soExactValue;
  begin
    if not (getvartype in [vtBinary,vtString,vtByteArray]) then //not binary, string or bytearray
    begin
      if not btnNextScan.enabled then
      begin
        //first scan
        case scantype.ItemIndex of
          0: result:=soExactValue;
          1: result:=soBiggerThan;
          2: result:=soSmallerThan;
          3: result:=soValueBetween;
          4: result:=soUnknownValue;
        end;
      end
      else
      begin
        //next scan
        case scantype.itemindex of
          0: result:=soExactValue;
          1: result:=soBiggerThan;
          2: result:=soSmallerThan;
          3: result:=soValueBetween;
          4: result:=soIncreasedValue;
          5: result:=soIncreasedValueBy;
          6: result:=soDecreasedValue;
          7: result:=soDecreasedValueBy;
          8: result:=soChanged;
          9: result:=soUnchanged;
          10: result:=soForgot;
        end;
      end;
    end;
  end;
end;


function TMainForm.getVarType2: TVariableType; //obsolete
begin
  result:=getVarType;

end;

function TMainForm.getVarType: TVariableType;
begin
  case VarType.ItemIndex of
    VARTYPE_INDEX_BINARY: result:=vtBinary; //binary
    VARTYPE_INDEX_BYTE: result:=vtByte; //byte
    VARTYPE_INDEX_WORD: result:=vtWord; //2 bytes
    VARTYPE_INDEX_DWORD: result:=vtDword; //4 bytes
    VARTYPE_INDEX_QWORD: result:=vtQword; //8 bytes
    VARTYPE_INDEX_SINGLE: result:=vtSingle; //float
    VARTYPE_INDEX_DOUBLE: result:=vtDouble; //double
    VARTYPE_INDEX_TEXT: result:=vtString; //text
    VARTYPE_INDEX_AOB: result:=vtByteArray; //array of byte
    VARTYPE_INDEX_ALL: result:=vtAll; //all, only for new memscan
    VARTYPE_INDEX_GROUPED: result:=vtGrouped; //grouped, only for memscan
    else
      result:=vtCustom;
  end;
end;

procedure TMainForm.setVarType(vt: TVariableType);
begin
  if vartype.enabled then
  begin
    case vt of
      vtBinary: vartype.itemindex:=VARTYPE_INDEX_BINARY;
      vtByte: vartype.itemindex:=VARTYPE_INDEX_BYTE;
      vtWord: vartype.itemindex:=VARTYPE_INDEX_WORD;
      vtDword: vartype.itemindex:=VARTYPE_INDEX_DWORD;
      vtQword: vartype.itemindex:=VARTYPE_INDEX_QWORD;
      vtSingle: vartype.itemindex:=VARTYPE_INDEX_SINGLE;
      vtDouble: vartype.itemindex:=VARTYPE_INDEX_DOUBLE;
      vtString: vartype.itemindex:=VARTYPE_INDEX_TEXT;
      vtByteArray: vartype.itemindex:=VARTYPE_INDEX_AOB;
      vtAll: vartype.itemindex:=VARTYPE_INDEX_ALL;
      vtGrouped: vartype.itemindex:=VARTYPE_INDEX_GROUPED;
    end;

    vartype.OnChange(vartype);
  end;
end;

procedure TMainForm.MemscanGuiUpdate(sender: TObject; totaladdressestoscan: qword; currentlyscanned: qword; foundcount: qword);
begin
  self.foundcount:=foundcount;
end;


procedure TMainForm.BoundsUpdate(sender: TObject);
var newminheight: integer;
begin
  newminheight:=gbScanOptions.top + gbScanOptions.Height + max(speedbutton2.Height, btnAddAddressManually.height ) + 10;

  if newminheight<>panel5.Constraints.MinHeight then
  begin
    gbScanOptions.OnChangeBounds:=nil;
    panel5.Constraints.MinHeight := gbScanOptions.top + gbScanOptions.Height + max(speedbutton2.Height, btnAddAddressManually.height ) + 10;
    gbScanOptions.OnChangeBounds:=@gbScanOptionsChangeBounds;
  end;

  boundsupdater.enabled:=false;
end;

procedure TMainForm.SpawnBoundsUpdater;
begin
  if boundsupdater=nil then
  begin
    boundsupdater:=TTimer.Create(self);
    boundsupdater.Interval:=500;
    boundsupdater.OnTimer:=@BoundsUpdate;
    boundsupdater.Enabled:=false;
  end;

  if boundsupdater.enabled=false then
    boundsupdater.enabled:=true;
end;

procedure TMainForm.reloadPreviousResults;
var
  l: tstringlist;
  i: integer;
  c: TListColumn;
  ssh: TSavedScanHandler;

  oldsizes: array of integer;
begin
  oldsizes:=[];
  l:=nil;
  setlength(oldsizes, foundlist3.ColumnCount);
  for i:=0 to foundlist3.columncount-1 do
    oldsizes[i]:=foundlist3.columns[i].Width;

  foundlist3.BeginUpdate;
  try
    cleanupPreviousResults;
    if getVarType in [vtGrouped, vtString, vtUnicodeString, vtByteArray] then exit;


    l:=tstringlist.create;


    c:=foundlist3.Columns.Add;
    c.caption:=rsPrevious;
    if c.Index=fActivePreviousResultColumn then
      c.tag:=foundlistColors.CompareToHeaderColor;

    c.visible:=(c.Index>=2) and miShowPreviousValue.checked and ((miOnlyShowCurrentCompareToColumn.Checked=false) or (c.index=fActivePreviousResultColumn));

    try
      ssh:=TSavedScanHandler.create(memscan.getScanFolder, 'TMP');
    except
      exit; //invalid state (e.g newscan)
    end;
    ssh.memscan:=memscan;
    ssh.AllowNotFound:=true;
    ssh.AllowRandomAccess:=true;
    PreviousResultList.add(ssh);



    memscan.getsavedresults(l);

    for i:=l.count-1 downto 0 do
    begin
      c:=foundlist3.Columns.Add;
      c.caption:=l[i];
      if c.Index=fActivePreviousResultColumn then
        c.tag:=foundlistColors.CompareToHeaderColor;

      c.visible:=(c.Index>=2) and miShowPreviousValue.checked and ((miOnlyShowCurrentCompareToColumn.Checked=false) or (c.index=fActivePreviousResultColumn));


      ssh:=TSavedScanHandler.create(memscan.getScanFolder, l[i], true);
      ssh.memscan:=memscan;
      ssh.AllowNotFound:=true;
      ssh.AllowRandomAccess:=true;

      PreviousResultList.Add(ssh);
    end;
  finally

    if l<>nil then
      freemem(l);

    if foundlist3.ColumnCount=length(oldsizes) then
    begin
      for i:=0 to length(oldsizes)-1 do
        foundlist3.Column[i].Width:=oldsizes[i];
    end
    else
      panel5resize(nil); //columncount changed

    foundlist3.EndUpdate;
  end;

end;

procedure TMainForm.cleanupPreviousResults;
//do a foundlist3.beginupdate first if this is just part of repopulating
var i: integer;
begin
  foundlist3.BeginUpdate;
  for i:=0 to PreviousResultList.Count-1 do
  begin
    if PreviousResultList[i]<>nil then
      TSavedScanHandler(PreviousResultList[i]).free;
  end;

  PreviousResultList.Clear;

  //first 2 columns are address and current value, the ones following are the previous value
  while foundlist3.Columns.count>2 do
    foundlist3.Columns.Delete(2);

  foundlist3.EndUpdate;
end;

procedure TMainForm.setActivePreviousResultColumn(c: integer);
var
  i: integer;
  {$ifdef darwin}
  s: string;
  {$endif}
begin
  if InsideSetActivePreviousResult then exit;

  InsideSetActivePreviousResult:=true;

  cbCompareToSavedScan.OnChange:=nil;

  if (c>=2) and (c<foundlist3.ColumnCount) then
  begin
    for i:=2 to foundlist3.ColumnCount-1 do
    begin
      foundlist3.Column[i].Tag:=0;


      {$ifdef darwin}
      s:=foundlist3.Column[i].caption;
      foundlist3.Column[i].caption:=s.DeQuotedString('*');
      {$endif}

      if miOnlyShowCurrentCompareToColumn.Checked then
      begin
        if (i>=2) then
          foundlist3.Columns[i].Visible:=(i=c) and miShowPreviousValue.checked; //only make the current compare column visible

      end
      else
        foundlist3.Columns[i].Visible:=(i>=2) and miShowPreviousValue.checked;

    end;

    fActivePreviousResultColumn:=c;

    if miOnlyShowCurrentCompareToColumn.Checked=false then //people that disable this likely want it the way the old CE showed it
    begin
      foundlist3.Column[c].tag:=foundlistColors.CompareToHeaderColor;

      {$ifdef darwin}
      s:=foundlist3.Column[c].caption;

      foundlist3.Column[c].caption:=s.QuotedString('*');
      {$endif}
    end;

    if (c-2)<PreviousResultList.count then
      currentlySelectedSavedResultname:=TSavedScanHandler(PreviousResultList[c-2]).name;

    if c>=3 then
    begin
      cbCompareToSavedScan.checked:=true;
      compareToSavedScan := True;
      if PreviousResultList.count>2 then  //last, first are default
      begin
        lblcompareToSavedScan.Visible := true;
        lblcompareToSavedScan.Caption := '('+currentlySelectedSavedResultname+')';
      end
      else
         lblcompareToSavedScan.Visible := false;
    end
    else
    begin
      cbCompareToSavedScan.checked := false;
      lblcompareToSavedScan.Visible := false;
    end;
  end;


  cbCompareToSavedScan.OnChange:=@cbCompareToSavedScanChange;

  foundlist3.Refresh;
  InsideSetActivePreviousResult:=false;
end;

initialization
  DecimalSeparator := '.';
  ThousandSeparator := ',';

  {$i MainUnit.lrs}

end.

open