cheat-engine/Cheat Engine/ProcessWindowUnit.pas

1437 lines
36 KiB
ObjectPascal
Raw Permalink Normal View History

2011-07-04 19:52:53 +00:00
unit ProcessWindowUnit;
{$MODE Delphi}
interface
uses
{$ifdef darwin}
macport,
{$endif}
{$ifdef windows}
jwawindows, windows,
{$endif}
LCLIntf, Messages, SysUtils, Classes, Graphics, Controls,
2017-04-16 19:55:21 +02:00
Forms, Dialogs, StdCtrls, ExtCtrls, CEFuncProc,CEDebugger, ComCtrls, ImgList,
Filehandler, Menus, LResources,{tlhelp32,}{$ifdef windows}vmxfunctions,{$endif} NewKernelHandler,
debugHelper{, KIcon}, commonTypeDefs, math,lcltype, syncobjs, Contnrs, betterControls;
2011-07-04 19:52:53 +00:00
2020-03-05 15:43:20 +01:00
type
TProcesslistlong = class(tthread)
private
processcount: integer;
process: array[0..9] of string;
procedure drawprocesses;
public
processlist: tlistbox;
procedure execute; override;
end;
{$ifdef windows}
2020-03-05 15:43:20 +01:00
TIconFetchEntry=record
processid: dword;
winhandle: hwnd; //optional
index: integer;
icon: HIcon; //gets filled in
end;
PIconFetchEntry=^TIconFetchEntry;
TIconFetchThread = class(TThread)
private
hasData: TEvent;
requestsList: TList; //just the PID
requestsListCS: TCriticalSection;
resolvedList: TList; //PID and HICON record
resolvedListCS: TCriticalSection;
procedure getIcon(e: PIconFetchEntry);
public
function queueIconFetch(processid: dword; winhandle: hwnd; index: integer): hicon; overload;
function queueIconFetch(processid: dword; index: integer): hicon; overload;
procedure reset;
procedure execute; override;
constructor create;
destructor destroy; override;
end;
{$endif}
2011-07-04 19:52:53 +00:00
type
{ TProcessWindow }
2011-07-04 19:52:53 +00:00
TProcessWindow = class(TForm)
btnNetwork: TButton;
btnAttachDebugger: TButton;
2016-08-19 03:20:12 +02:00
CancelButton: TButton;
FontDialog1: TFontDialog;
2020-03-05 15:43:20 +01:00
TabHeader: TPageControl;
2019-06-07 13:53:04 +02:00
plImageList: TImageList;
MainMenu1: TMainMenu;
MenuItem1: TMenuItem;
2019-04-07 07:52:21 +02:00
MenuItem2: TMenuItem;
MenuItem3: TMenuItem;
2019-04-07 21:57:08 +02:00
miConvertPIDToDecimal: TMenuItem;
2019-04-07 07:52:21 +02:00
miRefresh: TMenuItem;
miCreateProcess: TMenuItem;
miOpenFile: TMenuItem;
N2: TMenuItem;
miChangeFont: TMenuItem;
MenuItem4: TMenuItem;
MenuItem5: TMenuItem;
N1: TMenuItem;
miProcessListLong: TMenuItem;
miOwnProcessesOnly: TMenuItem;
2016-08-19 03:20:12 +02:00
OKButton: TButton;
2011-07-04 19:52:53 +00:00
Panel1: TPanel;
OpenDialog1: TOpenDialog;
OpenDialog2: TOpenDialog;
Panel3: TPanel;
Panel5: TPanel;
2011-07-04 19:52:53 +00:00
PopupMenu1: TPopupMenu;
InputPIDmanually1: TMenuItem;
Filter1: TMenuItem;
ProcessList: TListBox;
miShowInvisibleItems: TMenuItem;
2020-03-05 15:43:20 +01:00
tsApplications: TTabSheet;
tsProcesses: TTabSheet;
tsWindows: TTabSheet;
2017-04-14 22:53:59 +02:00
Timer1: TTimer;
procedure btnNetworkClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
2011-07-04 19:52:53 +00:00
procedure CancelButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure MenuItem5Click(Sender: TObject);
procedure miProcessListLongClick(Sender: TObject);
procedure miChangeFontClick(Sender: TObject);
procedure miOwnProcessesOnlyClick(Sender: TObject);
2019-04-07 07:52:21 +02:00
procedure miRefreshClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
procedure OKButtonClick(Sender: TObject);
procedure btnProcesslistClick(Sender: TObject);
procedure btnWindowListClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
procedure btnCreateThreadClick(Sender: TObject);
procedure btnAttachDebuggerClick(Sender: TObject);
procedure btnOpenFileClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
procedure InputPIDmanually1Click(Sender: TObject);
procedure Filter1Click(Sender: TObject);
procedure btnProcessWatchClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
procedure FormResize(Sender: TObject);
procedure btnProcessListLongClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure PopupMenu1Popup(Sender: TObject);
2011-07-04 19:52:53 +00:00
procedure ProcessListDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
procedure FormShow(Sender: TObject);
procedure ProcessListKeyPress(Sender: TObject; var Key: char);
procedure miShowInvisibleItemsClick(Sender: TObject);
procedure TabHeaderChange(Sender: TObject);
2020-03-05 15:43:20 +01:00
procedure TabHeaderResize(Sender: TObject);
2017-04-14 22:53:59 +02:00
procedure Timer1Timer(Sender: TObject);
2011-07-04 19:52:53 +00:00
private
{ Private declarations }
currentchar: integer;
2017-04-14 22:53:59 +02:00
wantedheight: integer;
2011-07-04 19:52:53 +00:00
ffilter: string;
2020-03-05 15:43:20 +01:00
{$ifdef windows}
2020-03-05 15:43:20 +01:00
IconFetchThread: TIconFetchThread;
{$endif}
2011-07-04 19:52:53 +00:00
processlistlong: tprocesslistlong;
procedure refreshlist;
2011-07-04 19:52:53 +00:00
procedure setbuttons;
procedure SetFilter(filter:string);
property filter:string read ffilter write setfilter;
procedure filterlist;
{$ifdef windows}
2020-03-05 15:43:20 +01:00
procedure iconFetchedEvent(sender: TObject; processid: dword; index: integer; icon: hicon);
{$endif}
2011-07-04 19:52:53 +00:00
public
{ Public declarations }
procedure PWOP(ProcessIDString:string);
published
2020-03-05 15:43:20 +01:00
property TabControl1: TPageControl read TabHeader;
2011-07-04 19:52:53 +00:00
end;
var
ProcessWindow: TProcessWindow;
2017-05-01 18:56:31 +02:00
commonProcessesList: tstringlist;
2011-07-04 19:52:53 +00:00
implementation
uses MainUnit, formsettingsunit, advancedoptionsunit,frmProcessWatcherUnit,
memorybrowserformunit, networkConfig, ProcessHandlerUnit, processlist, globals,
2023-10-20 17:32:15 +02:00
registry, fontSaveLoadRegistry, frmOpenFileAsProcessDialogUnit,
networkInterfaceApi, MainUnit2, DebuggerInterfaceAPIWrapper, gdbserverconnectdialog,
GDBServerDebuggerInterface, plugin;
2011-07-04 19:52:53 +00:00
resourcestring
rsIsnTAValidProcessID = '%s isn''t a valid processID';
rsPhysicalMemory = 'Physical Memory';
rsYouCanOnlyLoadEXEFiles = 'You can only load EXE files';
rsCreateProcess = 'Create Process';
rsOptionalLaunchParameters = 'Optional launch parameters';
rsAttachdebuggerornot = 'Are you sure you want to attach the debugger and not just open this process? (You can later on always attach the debugger)';
rsPleaseSelectAnotherProcess = 'Please select another process';
rsFirstSelectAProcess = 'First select a process!';
rsManualPID = 'Manual PID';
rsEnterTheProcessID = 'Enter the ProcessID';
rsFilter = 'Filter';
rsWhatAreYouLookingFor = 'What are you looking for?';
rsScanningClickToStop = 'Scanning (Click to stop)';
rsProcessListLong = 'Process List(long)';
rsProcessList = 'Process List';
2011-07-04 19:52:53 +00:00
rsApplications='Applications';
rsProcesses='Processes';
rsWindows='Windows';
2017-04-14 19:17:32 +02:00
var errortrace: integer;
2020-03-05 15:43:20 +01:00
{$IFDEF windows}
function SendMessageTimeout(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM; fuFlags, uTimeout: UINT; var lpdwResult: ptruint): LRESULT; stdcall; external 'user32' name 'SendMessageTimeoutA';
2020-03-05 15:43:20 +01:00
procedure TIconFetchThread.getIcon(e: PIconFetchEntry);
var
s: string;
HI: HICON;
tempptruint: ptruint;
begin
HI:=0;
if e^.winhandle<>0 then
begin
if SendMessageTimeout(e^.winhandle,WM_GETICON,ICON_SMALL,0,SMTO_ABORTIFHUNG, 200, tempptruint )<>0 then
begin
HI:=tempptruint;
if HI=0 then
begin
if SendMessageTimeout(e^.winhandle,WM_GETICON,ICON_SMALL2,0,SMTO_ABORTIFHUNG, 100, tempptruint )<>0 then
HI:=tempptruint;
if HI=0 then
if SendMessageTimeout(e^.winhandle,WM_GETICON,ICON_BIG,0,SMTO_ABORTIFHUNG, 50, tempptruint )<>0 then
HI:=tempptruint;
end;
end;
end;
if HI=0 then
begin
s:=GetFirstModuleName(e^.processid);
HI:=ExtractIcon(hinstance,pchar(s),0);
end;
if HI<>0 then
e^.icon:=HI
else
e^.icon:=HWND(-1);
resolvedListCS.Enter;
resolvedList.Add(e);
resolvedListCS.Leave;
end;
procedure TIconFetchThread.execute;
var
wr: TWaitResult;
listnotempty: boolean;
e: PIconFetchEntry;
pid: dword;
begin
2022-07-22 22:50:06 +02:00
NameThreadForDebugging('TIconFetchThread', ThreadID);
2020-03-05 15:43:20 +01:00
while not terminated do
begin
wr:=hasdata.WaitFor(1000);
if terminated then exit;
if wr=wrSignaled then
begin
listnotempty:=true;
while listnotempty do
begin
//fetch an item from the list
requestsListCS.enter;
e:=requestsList.last;
if e<>nil then
requestsList.Delete(requestsList.Count-1);
listnotempty:=requestsList.Count>0;
requestsListCS.leave;
//get the icon for this PID and then call the IconFetchedEvent
if e<>nil then
getIcon(e);
end;
end
else
if wr<>wrTimeout then break;
end;
end;
function TIconFetchThread.QueueIconFetch(processid: dword; winhandle: hwnd; index: integer): HIcon;
{
Queues an processid and window for processing
Changes the priority on request
Returns the icon if it has already been processed
}
var
found: boolean;
i: integer;
e: PIconFetchEntry;
begin
//first check if already in the list
result:=0;
found:=false;
requestsListCS.enter;
for i:=0 to requestsList.count-1 do
begin
e:=requestsList[i];
if (e^.processid=processid) and (e^.index=index) and (e^.winhandle=winhandle) then
begin
found:=true;
requestsList.Delete(i);
requestsList.Add(e);
break;
end;
end;
requestsListCS.leave;
if not found then
begin
//check if in the resolve queue, and if so, return it now
resolvedListCS.enter;
for i:=0 to resolvedList.count-1 do
begin
e:=resolvedList[i];
if (e^.processid=processid) and (e^.index=index) and (e^.winhandle=winhandle) then
begin
resolvedlist.Delete(i);
result:=e^.icon;
found:=true;
break;
end;
end;
resolvedListCS.leave;
end;
if not found then
begin
getmem(e,sizeof(TIconFetchEntry));
e^.processid:=processid;
e^.winhandle:=winhandle;
e^.index:=index;
e^.icon:=0;
requestsListCS.enter;
requestsList.Add(e);
requestsListCS.leave;
hasData.SetEvent;
end;
end;
function TIconFetchThread.QueueIconFetch(processid: dword; index: integer): HIcon;
begin
result:=QueueIconFetch(processid, 0, index);
end;
procedure TIconFetchThread.reset;
var i: integer;
begin
RemoveQueuedEvents(self);
resolvedListCS.enter;
for i:=0 to resolvedList.Count-1 do
if resolvedList[i]<>nil then
freemem(resolvedList[i]);
resolvedList.Clear;
resolvedListCS.leave;
requestsListCS.enter;
for i:=0 to requestsList.Count-1 do
if requestsList[i]<>nil then
freemem(requestsList[i]);
requestsList.clear;
requestsListCS.leave;
end;
constructor TIconFetchThread.create;
begin
hasData:=TEvent.create(nil,false,false,'');
requestsList:=Tlist.create;
requestsListCS:=TCriticalSection.Create;
resolvedList:=TList.create;
resolvedListCS:=TCriticalSection.create;
inherited create(false);
end;
destructor TIconFetchThread.Destroy;
begin
terminate;
hasdata.SetEvent;
waitfor;
reset;
hasdata.free;
requestsList.Free;
requestsListCS.free;
resolvedList.free;
resolvedListCS.free;
inherited destroy;
end;
{$ENDIF}
2020-03-05 15:43:20 +01:00
2011-07-04 19:52:53 +00:00
procedure TProcessListLong.drawprocesses;
var i: integer;
begin
if not terminated then
begin
processlist.Items.BeginUpdate;
for i:=0 to processcount-1 do
processlist.Items.Add(process[i]);
processlist.Items.EndUpdate;
processcount:=0;
end;
end;
procedure TProcessListLong.execute;
var i: dword;
h: thandle;
x: pchar;
modulename:string;
begin
{$ifdef windows}
2011-07-04 19:52:53 +00:00
i:=0;
while not terminated and (i<$FFFFFFFF) do
begin
h:=windows.OpenProcess(ifthen(GetSystemType<=6,$1f0fff, process_all_access),false,i);
2011-07-04 19:52:53 +00:00
if h<>0 then
begin
modulename:=getProcessnameFromProcessID(i);
process[processcount]:=inttohex(i,8)+'-'+modulename;
inc(processcount);
if processcount>=10 then
synchronize(drawprocesses);
closehandle(h);
end;
if ((i mod 4096)=0) then
if processcount>0 then synchronize(drawprocesses);
inc(i);
end;
if processcount>0 then synchronize(drawprocesses);
{$endif}
2011-07-04 19:52:53 +00:00
end;
2017-05-01 18:56:31 +02:00
procedure loadCommonProcessesList;
var
s: string;
i,j: integer;
begin
s:=cheatenginedir+'commonProcessesList.txt';
if FileExists(s) then //if the list exists
begin
if commonProcessesList=nil then commonProcessesList:=tstringlist.create;
try
commonProcessesList.LoadFromFile(s{$if FPC_FULLVERSION >= 030200}, true{$endif});
2017-05-01 18:56:31 +02:00
for i:=commonProcessesList.Count-1 downto 0 do
begin
j:=pos('#', commonProcessesList[i]);
if j>0 then commonProcessesList[i]:=copy(commonProcessesList[i], 1, j-1);
commonProcessesList[i]:=uppercase(trim(commonProcessesList[i]));
if commonProcessesList[i]='' then commonProcessesList.Delete(i);
end;
except
end;
end;
2017-05-01 18:56:31 +02:00
end;
function isInCommonProcessesList(processname: string): boolean;
var
i:integer;
begin
if commonProcessesList=nil then exit(false);
for i:=0 to commonProcessesList.Count-1 do
if commonProcessesList[i]=uppercase(copy(processname,10)) then exit(true);
result:=false;
end;
2011-07-04 19:52:53 +00:00
procedure TProcessWindow.filterlist;
var
i:integer;
{$IFDEF WINDOWS}
pli: PProcessListInfo;
{$ENDIF}
s: string;
2011-07-04 19:52:53 +00:00
begin
if (filter='') and (commonProcessesList=nil) then exit;
ffilter:=uppercase(ffilter);
2011-07-04 19:52:53 +00:00
i:=0;
while i<processlist.Items.Count do
begin
{$IFDEF WINDOWS}
pli:=PProcessListInfo(processlist.items.Objects[i]);
{$ENDIF}
if ((ffilter<>'') and (pos(ffilter,uppercase(processlist.Items[i]))=0)) or isInCommonProcessesList(processlist.Items[i]) then
begin
{$IFDEF WINDOWS}
if pli<>nil then
begin
if pli^.processIcon>0 then
begin
if pli^.processID<>GetCurrentProcessId then
DestroyIcon(pli^.processIcon);
pli^.processIcon:=0;
end;
freememandnil(pli);
end;
{$ENDIF}
processlist.Items.Delete(i);
end
2011-07-04 19:52:53 +00:00
else
inc(i);
end;
end;
procedure TProcesswindow.SetFilter(filter:string);
begin
ffilter:=filter;
refreshlist;
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.CancelButtonClick(Sender: TObject);
begin
mainform.canceled:=true;
//ProcessWindow.close;
ModalResult:=mrCancel;
end;
{$ifdef windows}
2020-03-05 15:43:20 +01:00
procedure TProcessWindow.iconFetchedEvent(sender: TObject; processid: dword; index: integer; icon: hicon);
var
i: integer;
pli: PProcessListInfo;
begin
if (index>=0) and (index<processlist.items.count) then
begin
pli:=PProcessListInfo(processlist.Items.Objects[index]);
if pli<>nil then
begin
if pli^.processID=processid then //making sure the list didn't change
begin
if pli^.processIcon=0 then
begin
pli^.processIcon:=icon;
end
else
begin
if (icon<>0) and (icon<>HWND(-1)) and (processid<>getcurrentprocessid) then
begin
DestroyIcon(icon); //not needed anymore (duplicates shouldn't happen...)
end;
end;
end;
end;
end;
end;
{$endif}
procedure TProcessWindow.FormCreate(Sender: TObject);
var
x: array of integer;
reg: tregistry;
begin
{$ifdef darwin}
{ProcessList.AnchorSideTop:=ProcessWindow.AnchorSideTop;
ProcessList.AnchorSideLeft:=TabHeader.AnchorSideLeft;
ProcessList.AnchorSideRight:=TabHeader.AnchorSideRight;
ProcessList.AnchorSideBottom:=TabHeader.AnchorSideBottom;
ProcessList.Anchors:=TabHeader.Anchors;
TabHeader.TabIndex:=1;
TabHeader.Visible:=false; }
tsWindows.TabVisible:=false;
tsWindows.Visible:=false;
{$endif}
2022-07-22 22:50:06 +02:00
{$ifdef windows}
IconFetchThread:=TIconFetchThread.create;
{$endif}
2020-03-05 15:43:20 +01:00
tsApplications.Caption:=rsApplications;
tsProcesses.Caption:=rsProcesses;
tsWindows.Caption:=rsWindows;
setlength(x,0);
if LoadFormPosition(self,x) then
begin
autosize:=false;
2017-04-16 19:55:21 +02:00
if length(x)>0 then
TabHeader.TabIndex:=x[0];
2017-04-16 19:55:21 +02:00
if length(x)>1 then
begin
miOwnProcessesOnly.checked:=x[1]<>0;
ProcessesCurrentUserOnly:=x[1]<>0;
end;
end
else
refreshlist;
reg:=tregistry.create;
try
2021-11-16 20:58:25 +01:00
if reg.OpenKey('\Software\'+strCheatEngine+'\Process Window\Font'+darkmodestring,false) then
LoadFontFromRegistry(processlist.Font, reg)
else
processlist.font.color:=colorset.FontColor;
finally
reg.free;
end;
2023-10-20 17:32:15 +02:00
if formSettings.cbUseGDBServer.checked then
btnNetwork.Caption:='Connect to GDB';
end;
procedure TProcessWindow.FormDestroy(Sender: TObject);
2018-06-11 15:36:17 +02:00
var x: array of integer;
begin
2018-06-11 15:36:17 +02:00
setlength(x,3);
x[0]:=TabHeader.TabIndex;
2018-06-11 15:36:17 +02:00
x[1]:=ifthen(miOwnProcessesOnly.checked,1,0);
SaveFormPosition(self,x);
end;
procedure TProcessWindow.MenuItem5Click(Sender: TObject);
begin
end;
procedure TProcessWindow.miProcessListLongClick(Sender: TObject);
begin
btnProcessListLongClick(nil);
end;
procedure TProcessWindow.miChangeFontClick(Sender: TObject);
var reg: tregistry;
begin
fontdialog1.font.assign(processlist.font);
if fontdialog1.execute then
begin
//apply settings
processlist.font.assign(FontDialog1.Font);
2017-04-14 22:53:59 +02:00
//processlist.Canvas.Refresh;
Timer1Timer(timer1);
processlist.Repaint;
reg:=tregistry.create;
try
2021-11-16 20:58:25 +01:00
if reg.OpenKey('\Software\'+strCheatEngine+'\Process Window\Font'+darkmodestring,true) then
SaveFontToRegistry(FontDialog1.Font, reg);
finally
reg.free;
end;
end;
end;
procedure TProcessWindow.miOwnProcessesOnlyClick(Sender: TObject);
begin
ProcessesCurrentUserOnly:=miOwnProcessesOnly.checked;
refreshlist;
end;
2019-04-07 07:52:21 +02:00
procedure TProcessWindow.miRefreshClick(Sender: TObject);
begin
refreshList;
end;
procedure TProcessWindow.btnNetworkClick(Sender: TObject);
2023-10-20 17:32:15 +02:00
var
host: string;
port: word;
begin
2023-10-20 17:32:15 +02:00
if formsettings.cbUseGDBServer.checked then
begin
2023-10-20 17:32:15 +02:00
if MessageDlg('Connecting to GDB using this option instead of attaching the debugger to the native process will force the use of GDB read and write memory functions which is a lot slower, and you will not have access to local symbol info and some other tools you may be used to. Are you sure?', mtWarning, [mbyes, mbno],0)<>mryes then exit;
GDBReadProcessMemory:=true;
GDBWriteProcessMemory:=true;
2023-11-13 01:47:23 +01:00
SkipVirtualProtectEx:=true;
2023-10-20 17:32:15 +02:00
outputdebugstring('Using GDBServer debugger interface');
if CurrentDebuggerInterface<>nil then
freeandnil(CurrentDebuggerInterface);
2023-10-20 17:32:15 +02:00
if formsettings.cbLaunchGDBServer.Checked then
begin
port:=strtoint(formsettings.edtGDBPort.Text);
CurrentDebuggerInterface:=TGDBServerDebuggerInterface.createAndConnect(formsettings.edtGDBServerCommand.Text, 'localhost', port);
end
else
begin
2023-10-20 17:32:15 +02:00
//spawn a dialog asking
if getGDBHostAndPort(host, port) then
CurrentDebuggerInterface:=TGDBServerDebuggerInterface.connectToExistingServer(host,port);
end;
if CurrentDebuggerInterface<>nil then
begin
tabheader.ShowTabs:=false;
TabHeaderResize(nil);
if TabHeader.TabIndex<>1 then
TabHeader.Tabindex:=1;
refreshlist;
2023-10-20 17:32:15 +02:00
processlist.SetFocus;
btnAttachDebugger.Visible:=false;
if processlist.Count=0 then
begin
//this is a processless system
MainForm.ProcessLabel.caption:='Remote System';
processhandler.processid:=$FFFFFFFE;
processhandler.processhandle:=-2;
startdebuggerifneeded(false);
onAPIPointerChange:=TGDBServerDebuggerInterface(currentdebuggerinterface).OnApiPointerChange;
onAPIPointerChange(nil);
modalresult:=mrok;
end;
end;
end
else
begin
if frmNetworkConfig=nil then
frmNetworkConfig:=tfrmNetworkConfig.create(self);
if frmNetworkConfig.ShowModal=mrok then
begin
tabheader.ShowTabs:=false;
TabHeaderResize(nil);
if TabHeader.TabIndex<>1 then
TabHeader.Tabindex:=1;
refreshlist;
processlist.SetFocus;
end;
end;
end;
procedure TProcessWindow.Button1Click(Sender: TObject);
begin
end;
2011-07-04 19:52:53 +00:00
procedure TProcessWindow.setbuttons;
begin
end;
procedure TProcessWindow.PWOP(ProcessIDString:string);
var i:integer;
begin
val('$'+ProcessIDString,ProcessHandler.processid,i);
if i<>0 then raise exception.Create(Format(rsIsnTAValidProcessID, [processidstring]));
if Processhandle<>0 then
ProcessHandler.ProcessHandle:=0;
with mainform do
begin
if GetSystemType>=4 then
begin
cbSpeedhack.checked:=false;
cbSpeedhack.Enabled:=true;
cbunrandomizer.Checked:=false;
cbunrandomizer.Enabled:=true;
end;
end;
{$ifdef windows}
if (processid<>0) and (UseFileAsMemory or Usephysical or usephysicaldbvm) then
begin
//swap back to processmemory
UseFileAsMemory:=false;
Usephysical:=false;
usephysicaldbvm:=false;
if formsettings.cbKernelOpenProcess.checked then
UseDBKOpenProcess
else
DONTUseDBKOpenProcess;
if formsettings.cbKernelQueryMemoryRegion.checked then
UseDBKQueryMemoryRegion
else
DONTUseDBKQueryMemoryRegion;
if formsettings.cbKernelReadWriteProcessMemory.checked then
UseDBKReadWriteMemory
else
DONTUseDBKReadWriteMemory;
end;
{$endif}
2011-07-04 19:52:53 +00:00
2023-10-20 17:32:15 +02:00
if (CurrentDebuggerInterface<>nil) and (CurrentDebuggerInterface is TGDBServerDebuggerInterface) then
begin
//use the currently selected processid for startdebuggerifneeded (for the vAttach packet)
processhandler.processhandle:=-2;
startdebuggerifneeded(false);
onAPIPointerChange:=TGDBServerDebuggerInterface(currentdebuggerinterface).OnApiPointerChange;
onAPIPointerChange(nil);
processhandler.processid:=$fffffffe; //the processid is not needed anymore
end
else
Open_Process;
2011-07-04 19:52:53 +00:00
2023-08-25 08:48:13 +02:00
if ProcessHandle=0 then
begin
if not runningAsAdmin then
begin
raise exception.Create('Failed opening process. Likely due to lack of admin rights');
end;
end;
2011-07-04 19:52:53 +00:00
ProcessSelected:=true;
{$ifdef windows}
2011-07-04 19:52:53 +00:00
if (processid=0) and ((formsettings.cbKernelReadWriteProcessMemory.checked) or (dbvm_version>=$ce000004)) then
begin
ProcessHandler.processid:=$FFFFFFFF;
if dbvm_version>=$ce000004 then
DBKPhysicalMemoryDBVM
else
DBKPhysicalMemory;
ProcessHandler.ProcessHandle:=$FFFFFFFF;
end
else
begin
if usephysical or usephysicaldbvm then
DBKProcessMemory;
end;
{$endif}
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.OKButtonClick(Sender: TObject);
var ProcessIDString: String;
begin
2023-08-25 08:48:13 +02:00
try
Outputdebugstring('OK button click');
if Processlist.ItemIndex>-1 then
begin
unpause;
DetachIfPossible;
2011-07-04 19:52:53 +00:00
2023-08-25 08:48:13 +02:00
ProcessIDString:=copy(ProcessList.Items[Processlist.ItemIndex], 1, pos('-',ProcessList.Items[Processlist.ItemIndex])-1);
2011-07-04 19:52:53 +00:00
2023-10-20 17:32:15 +02:00
Outputdebugstring('calling PWOP');
2023-08-25 08:48:13 +02:00
PWOP(ProcessIDString);
2023-08-25 08:48:13 +02:00
if TabHeader.TabIndex=0 then
MainForm.ProcessLabel.caption:=ProcessIDString+'-'+extractfilename(getProcessPathFromProcessID(processid))
else
MainForm.ProcessLabel.caption:=ProcessList.Items[Processlist.ItemIndex];
Modalresult:=MROK;
//ProcessWindow.close;
end;
2011-07-04 19:52:53 +00:00
2023-08-25 08:48:13 +02:00
except
on e: exception do
MessageDlg(e.Message,mtError,[mbok],0);
end;
//outputdebugstring('After ok click handler');
2011-07-04 19:52:53 +00:00
end;
//button1click specific:
procedure TProcessWindow.btnProcesslistClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
begin
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.btnWindowListClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
begin
//miSkipSystemProcesses.visible:=false;
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.btnCreateThreadClick(Sender: TObject);
var parameters: string;
begin
if Opendialog1.Execute then
begin
if Uppercase(extractfileext(opendialog1.FileName))<>'.EXE' then raise Exception.Create(rsYouCanOnlyLoadEXEFiles);
parameters:='';
if not InputQuery(rsCreateProcess, rsOptionalLaunchParameters, parameters) then exit;
unpause;
detachIfPossible;
Debuggerthread:=TDebuggerThread.MyCreate2(opendialog1.FileName, parameters);
if not Debuggerthread.running then exit;
mainForm.ProcessLabel.caption:=IntToHex(processid,8)+'-'+ExtractFileName(opendialog1.FileName);
mainform.debugproc:=true;
memorybrowser.show;
modalresult:=mrOk;
end;
end;
procedure TProcessWindow.btnAttachDebuggerClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
var ProcessIDString: String;
i: Integer;
oldpid,newpid: dword;
starttime: qword;
2011-07-04 19:52:53 +00:00
begin
oldpid:=processid;
2011-07-04 19:52:53 +00:00
if Processlist.ItemIndex>-1 then
begin
if MessageDlg(rsAttachdebuggerornot, mtConfirmation, [mbyes, mbno], 0)=mryes then
begin
2011-07-04 19:52:53 +00:00
unpause;
DetachIfPossible;
ProcessIDString:='';
i:=1;
while ProcessList.Items[Processlist.ItemIndex][i]<>'-' do
begin
ProcessIDString:=ProcessIDString+ProcessList.Items[Processlist.ItemIndex][i];
inc(i);
end;
val('$'+ProcessIDString,newpid,i);
2011-07-04 19:52:53 +00:00
if (Processhandle<>0) and (oldpid<>newpid) then
2011-07-04 19:52:53 +00:00
begin
CloseHandle(ProcessHandle);
ProcessHandler.ProcessHandle:=0;
end;
try
if processid=GetCurrentProcessId then raise exception.create(rsPleaseSelectAnotherProcess);
2011-07-04 19:52:53 +00:00
starttime:=GetTickCount64;
Debuggerthread:=TDebuggerThread.MyCreate2(newpid);
except
on e: exception do
begin
debuggerthread:=nil;
MessageDlg(e.message, mtError,[mbok],0);
exit;
end;
end;
2011-07-04 19:52:53 +00:00
OutputDebugString('Debugger attach time='+(GetTickCount64-starttime).ToString);
2011-07-04 19:52:53 +00:00
mainform.ProcessLabel.Caption:=ProcessList.Items[Processlist.ItemIndex];
ProcessSelected:=true;
mainform.debugproc:=true;
modalresult:=mrOK;
end
end else showmessage(rsFirstSelectAProcess);
end;
procedure TProcessWindow.btnOpenFileClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
begin
{$ifdef windows}
2011-07-04 19:52:53 +00:00
if opendialog2.execute then
begin
if frmOpenFileAsProcessDialog=nil then
frmOpenFileAsProcessDialog:=tfrmOpenFileAsProcessDialog.create(self);
2011-07-04 19:52:53 +00:00
if frmOpenFileAsProcessDialog.showmodal=mrok then
begin
DBKFileAsMemory(opendialog2.filename, frmOpenFileAsProcessDialog.startaddress);
processselected:=true;
ProcessHandler.ProcessHandle:=QWORD(-2);
MainForm.ProcessLabel.caption:=extractfilename(opendialog2.FileName);
MainForm.miSaveFile.visible:=true;
ProcessHandler.processid:=$FFFFFFFF;
Processhandler.is64Bit:=frmOpenFileAsProcessDialog.rb64.checked;
modalresult:=mrok;
end;
2011-07-04 19:52:53 +00:00
end;
{$else}
MessageDlg('Not yet implemented', mtError,[mbok],0);
{$endif}
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.InputPIDmanually1Click(Sender: TObject);
var pid: string;
begin
pid:='0';
if InputQuery(rsManualPID, rsEnterTheProcessID+':', pid) then
begin
unpause;
DetachIfPossible;
pwop(pid);
MainForm.ProcessLabel.caption:=pid;
modalresult:=mrok;
end;
end;
procedure TProcessWindow.Filter1Click(Sender: TObject);
var fltr: string;
begin
fltr:=filter;
2011-07-04 19:52:53 +00:00
if inputquery(rsFilter, rsWhatAreYouLookingFor, fltr) then
filter:=fltr;
end;
procedure TProcessWindow.btnProcessWatchClick(Sender: TObject);
2011-07-04 19:52:53 +00:00
begin
if frmprocesswatcher=nil then
frmprocesswatcher:=tfrmprocesswatcher.Create(mainform);
2011-07-04 19:52:53 +00:00
frmprocesswatcher.show;
modalresult:=mrcancel;
end;
procedure TProcessWindow.FormResize(Sender: TObject);
begin
//reset the button positions
// setbuttons;
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.btnProcessListLongClick(Sender: TObject);
begin
if processlistlong=nil then
begin
processlist.Clear;
miProcessListLong.Caption:=rsScanningClickToStop;
2011-07-04 19:52:53 +00:00
processlistlong:=tprocesslistlong.create(true);
processlistlong.processlist:=processlist;
processlistlong.start;
end
else
begin
miProcessListLong.Caption:=rsProcessListLong;
2011-07-04 19:52:53 +00:00
processlistlong.terminate;
processlistlong.WaitFor;
processlistlong.Free;
processlistlong:=nil;
end;
end;
procedure TProcessWindow.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
if processlistlong<>nil then
begin
processlistlong.terminate;
processlistlong.WaitFor;
processlistlong.Free;
processlistlong:=nil;
miProcessListLong.Caption:=rsProcessListLong;
2011-07-04 19:52:53 +00:00
end;
position:=poDesigned;
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.PopupMenu1Popup(Sender: TObject);
begin
miShowInvisibleItems.visible:=tabheader.TabIndex=2;
end;
2011-07-04 19:52:53 +00:00
procedure TProcessWindow.ProcessListDrawItem(Control: TWinControl;
Index: Integer; Rect: TRect; State: TOwnerDrawState);
2019-04-07 21:57:08 +02:00
var
i: integer;
t: string;
sep: integer;
pids: string;
pid: dword;
{$IFDEF WINDOWS}
2020-03-05 15:43:20 +01:00
pli: PProcessListInfo;
{$ENDIF}
2011-07-04 19:52:53 +00:00
begin
2017-04-14 22:53:59 +02:00
wantedheight:=ProcessList.canvas.TextHeight('QqJjWwSs')+3;
{i:=ProcessList.canvas.TextHeight('QqJjWwSs')+3;
if processlist.itemheight<i then ProcessList.ItemHeight:=i; }
2011-07-04 19:52:53 +00:00
processlist.Canvas.FillRect(rect);
2017-04-14 22:53:59 +02:00
{
i:=ProcessList.canvas.TextHeight('QqJjWwSs')+3;
2017-04-14 22:53:59 +02:00
if processlist.itemheight<i then ProcessList.ItemHeight:=i;}
2011-07-04 19:52:53 +00:00
2019-04-07 21:57:08 +02:00
t:=processlist.Items[index];
if miConvertPIDToDecimal.checked then
begin
sep:=pos('-',t);
if sep<>0 then
begin
try
pids:=copy(t,1,sep-1);
pid:=strtoint('$'+pids);
2019-04-08 09:33:08 +02:00
t:=format('%.8d',[pid])+copy(t,sep);
2019-04-07 21:57:08 +02:00
except
end;
end;
end;
if odSelected in state then
processlist.Canvas.font.color:=clHighlightText
else
processlist.Canvas.font.color:=processlist.font.color;
2019-04-07 21:57:08 +02:00
processlist.Canvas.TextOut(rect.Left+rect.Bottom-rect.Top+3,rect.Top,t);
if getConnection<>nil then exit;
{$ifdef windows}
if getprocessicons and (processlist.Items.Objects[index]<>nil) then
2020-03-05 15:43:20 +01:00
begin
pli:=PProcessListInfo(processlist.Items.Objects[index]);
if pli^.processIcon=0 then
pli^.processIcon:=IconFetchThread.queueIconFetch(pli^.processID, pli^.winhandle, index);
if (pli^.processIcon<>0) and (pli^.processIcon<>HWND(-1)) then
DrawIconEx(processlist.Canvas.Handle, rect.left, rect.Top, pli^.processIcon, rect.Bottom-rect.Top,rect.Bottom-rect.Top,0,0,DI_NORMAL);
end;
{$endif}
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.FormShow(Sender: TObject);
var
tr: trect;
preferedwidth: integer;
tabwidth: integer;
pc: integer;
s: string;
i: integer;
2011-07-04 19:52:53 +00:00
begin
if getconnection<>nil then
tabheader.ShowTabs:=true;
OKButton.Constraints.MinHeight:=trunc(1.2*btnAttachDebugger.height);
CancelButton.Constraints.MinHeight:=OKButton.Constraints.MinHeight;
2017-05-01 18:56:31 +02:00
loadCommonProcessesList;
2017-04-14 19:50:43 +02:00
errortrace:=100;
try
errortrace:=101;
processlist.canvas.Refresh;
errortrace:=102;
ProcessList.ItemHeight:=max(processlist.canvas.TextHeight('QqJjWwSs')+3, canvas.TextHeight('QqJjWwSs')+3);
errortrace:=103;
currentchar:=1;
errortrace:=104;
refreshlist;
errortrace:=105;
2011-07-04 19:52:53 +00:00
if autosize then
begin
autosize:=false;
2019-02-03 02:04:51 +01:00
//first run or no saving positions
preferedwidth:=max(clientwidth, canvas.TextWidth(' XXXXXXXX - XXXXXXXXXXXXXXXXXXXXXX '));
pc:=tabheader.PageCount;
tabwidth:=0;
for i:=0 to pc-1 do
begin
tr:=tabheader.TabRect(i);
tabwidth:=tabwidth+tr.Width;
end;
tabwidth:=tabwidth+ canvas.TextWidth(' ');
if tabwidth>preferedwidth then
preferedwidth:=tabwidth;
clientwidth:=preferedwidth;
2019-02-03 02:04:51 +01:00
height:=mainform.Height-(mainform.height div 3);
position:=poDesigned;
position:=poMainFormCenter;
end;
2017-04-14 19:50:43 +02:00
errortrace:=106;
2017-07-19 09:42:28 +02:00
2017-07-19 09:42:28 +02:00
processlist.SetFocus;
2017-04-14 19:50:43 +02:00
except
on e:exception do
raise exception.create('FormShow exception ('+e.message+') at section '+inttostr(errortrace));
2016-08-19 03:20:12 +02:00
2017-04-14 19:50:43 +02:00
end;
2011-07-04 19:52:53 +00:00
end;
procedure TProcessWindow.ProcessListKeyPress(Sender: TObject; var Key: char);
begin
if key=#8 then
filter:=copy(filter, 1, length(filter)-1)
else
2013-10-05 23:53:52 +00:00
if key in [chr(32)..chr(128)] then
filter:=filter+key;
end;
procedure TProcessWindow.RefreshList;
var
i: integer;
oldselectionindex: integer;
oldselection: string;
found: boolean;
2017-04-14 19:17:32 +02:00
2011-07-04 19:52:53 +00:00
begin
{$ifdef windows}
2020-03-05 15:43:20 +01:00
IconFetchThread.reset;
{$endif}
2020-03-05 15:43:20 +01:00
processlist.Items.BeginUpdate;
2017-04-14 19:17:32 +02:00
try
oldselectionindex:=processlist.ItemIndex;
2017-04-14 19:17:32 +02:00
if oldselectionindex<>-1 then
oldselection:=processlist.Items[oldselectionIndex];
case TabHeader.TabIndex of
2017-04-14 19:17:32 +02:00
0:
begin
{$ifdef windows}
2017-04-14 19:17:32 +02:00
getwindowlist2(processlist.Items);
{$else}
getapplicationlist(processlist.items);
{$endif}
2017-04-14 19:17:32 +02:00
end;
2017-04-14 19:17:32 +02:00
1:
begin
getprocesslist(processlist.items);
end;
2:
begin
{$ifdef windows}
2017-04-14 19:17:32 +02:00
GetWindowList(processlist.Items, miShowInvisibleItems.Checked);
processlist.ItemIndex:=processlist.Items.Count-1;
{$else}
getprocesslist(processlist.items);
{$endif}
2017-04-14 19:17:32 +02:00
end;
end;
2017-04-14 19:17:32 +02:00
filterlist;
2017-04-14 19:17:32 +02:00
if oldselectionindex=-1 then
begin
processlist.ItemIndex:=processlist.Items.Count-1; //go to the end
end
else
begin
2017-04-14 19:17:32 +02:00
i:=processlist.Items.IndexOf(oldselection);
if i>=0 then
begin
processlist.ItemIndex:=i;
end
else
begin
//strip out the processid part and search for a entry with the appropriate processname (e.g restarted game)
oldselection:=copy(oldselection,pos('-',oldselection)+1,length(oldselection));
2017-04-14 19:17:32 +02:00
found:=false;
2020-08-21 19:04:17 +02:00
for i:=processlist.Items.Count-1 downto 0 do
2017-04-14 19:17:32 +02:00
if pos(oldselection, processlist.items[i])>0 then
begin
processlist.ItemIndex:=i;
found:=true;
2017-04-14 19:17:32 +02:00
break;
end;
2017-04-14 19:17:32 +02:00
if not found then
processlist.ItemIndex:=processlist.Items.Count-1;
end;
end;
if filter<>'' then
caption:=rsProcessList+' : *'+filter+'*'
else
caption:=rsProcessList;
{$ifdef windows}
2017-04-14 19:17:32 +02:00
if formsettings.cbKernelReadWriteProcessMemory.checked or (dbvm_version>=$ce000004) then //driver is active
begin
if TabHeader.TabIndex<=2 then //other script are on their own
processlist.Items.Insert(0, '00000000-['+rsPhysicalMemory+']');
2017-04-14 19:17:32 +02:00
end;
{$endif}
finally
processlist.items.EndUpdate;
2017-04-14 19:17:32 +02:00
end;
end;
procedure TProcessWindow.miShowInvisibleItemsClick(Sender: TObject);
begin
refreshList;
end;
procedure TProcessWindow.TabHeaderChange(Sender: TObject);
begin
refreshList;
2011-07-04 19:52:53 +00:00
end;
2020-03-05 15:43:20 +01:00
procedure TProcessWindow.TabHeaderResize(Sender: TObject);
var p: tpoint;
begin
p:=TabHeader.ClientToParent(point(0,0));
//if TabHeader.ShowTabs=false then
// processlist.top:=tabheader.top
// else
processlist.Top:=p.Y;
2020-03-05 15:43:20 +01:00
processlist.Left:=p.X;
processlist.Width:=TabHeader.ClientWidth;
// if tabheader.ShowTabs=false then
processlist.Height:=TabHeader.ClientHeight
// else
// processlist.Height:=tabheader.Height;
2020-03-05 15:43:20 +01:00
end;
2017-04-14 22:53:59 +02:00
procedure TProcessWindow.Timer1Timer(Sender: TObject);
2020-03-05 15:43:20 +01:00
var
i: integer;
{$ifdef windows}
2020-03-05 15:43:20 +01:00
e: PIconFetchEntry;
{$endif}
2017-04-14 22:53:59 +02:00
begin
try
if processlist.itemheight<>wantedheight then
begin
ProcessList.ItemHeight:=wantedheight;
processlist.canvas.Refresh;
processlist.Repaint;
end;
2020-03-05 15:43:20 +01:00
{$ifdef windows}
2020-03-05 15:43:20 +01:00
IconFetchThread.resolvedListCS.enter;
try
e:=nil;
for i:=0 to IconFetchThread.resolvedList.count-1 do
begin
e:=PIconFetchEntry(IconFetchThread.resolvedList[i]);
iconFetchedEvent(IconFetchThread, e^.processid, e^.index, e^.icon);
freemem(e);
end;
IconFetchThread.resolvedList.clear;
finally
IconFetchThread.resolvedListCS.leave;
end;
if e<>nil then processlist.Repaint;
{$endif}
2020-03-05 15:43:20 +01:00
2017-04-14 22:53:59 +02:00
except
timer1.enabled:=false;
showmessage('timer issue');
end;
end;
2011-07-04 19:52:53 +00:00
initialization
{$i ProcessWindowUnit.lrs}
end.