Reputation: 194
I have an application that starts with a regular window and includes a "hide" button. When this button is clicked, the application continues running and is visible in the Task Manager, but it no longer has any visible window.
I've tried several methods to programmatically find this application in Delphi:
Using GetWindowText
: This doesn't work because the application doesn't have a window when it's hidden.
Using TProcessEntry32.szExeFile
: This is unreliable because:
TProcessEntry32
listUsing WMI queries: this also fails to find the application by the name visible in the Task Manager.
My question is: how can I create a function in Delphi to detect whether this application is running, given the following constraints?
=== edit ===
The application that I'm struggling with is designed for dishonestly manipulating user activity tracking. As previously mentioned, it initially appears as a window but can be later hidden from view. Even when hidden, it continues to simulate user activity. As mentioned earlier, users can change its name and start it, so the only constant in this case would be the name visible in the task manager. Unfortunately, I cannot locate it when it's hidden. Below is the code I'm currently using; please let me know if there are any mistakes.
This code works when application is visible (does not work when hidden)
var WinTitle : array[0..256] of Char;
begin
if GetWindowText(Wnd, WinTitle, SizeOf(WinTitle)) > 0 then
begin
if pos('GDollar', WinTitle) > 0 then
PostMessage(Wnd, WM_CLOSE, 0, 0);
end;
Result := True;
end;
procedure TForm1.btn_1Click(Sender: TObject);
begin
EnumWindows(@EnumWindowsProc, 0);
end;
I tried this - but no luck (and it's - obviously - painfully slow).
procedure TForm1.btn_2Click(Sender: TObject);
var PHandle, FHandle: THandle;
Process:TProcessEntry32;
Done, Next: Boolean;
WinTitle : array[0..256] of Char;
pn : String;
begin
FHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
Process.dwSize := Sizeof(Process);
Next := Process32First(FHandle, Process);
while Next do
begin
pn := GetProcessNameByPID(GetHWndByPID(process.th32ProcessID));
if pos('GDollar', pn) > 0 then
ShowMessage(pn);
Next := Process32Next(FHandle,Process);
end;
CloseHandle(FHandle);
end;
function TForm1.GetHWndByPID(const hPID: THandle): THandle;
type
PEnumInfo = ^TEnumInfo;
TEnumInfo = record
ProcessID: DWORD;
HWND: THandle;
end;
function EnumWindowsProc(Wnd: DWORD; var EI: TEnumInfo): Bool; stdcall;
var PID: DWORD;
begin
GetWindowThreadProcessID(Wnd, @PID);
Result := (PID <> EI.ProcessID) or (not IsWindowVisible(WND)) or (not IsWindowEnabled(WND));
if not Result then EI.HWND := WND;
end;
function FindMainWindow(PID: DWORD): DWORD;
var EI: TEnumInfo;
begin
EI.ProcessID := PID;
EI.HWND := 0;
EnumWindows(@EnumWindowsProc, Integer(@EI));
Result := EI.HWND;
end;
begin
if hPID <> 0
then Result:=FindMainWindow(hPID)
else Result:=0;
end;
function TForm1.GetProcessNameByPID(const PID: DWORD): string;
var
objSWbemLocator, objWMIService: OLEVariant;
colItems: OLEVariant;
colItem: OLEVariant;
oEnum: IEnumvariant;
iValue: LongWord;
begin
Result := ''; // Initialize result to empty string
objSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
objWMIService := objSWbemLocator.ConnectServer('localhost','root\cimv2', '','');
colItems := objWMIService.ExecQuery(Format('SELECT * FROM Win32_Process WHERE ProcessId=%d', [PID]), 'WQL', 0);
oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
if oEnum.Next(1, colItem, iValue) = 0 then
begin
Result := colItem.Name;
colItem := Unassigned;
end;
end;
Upvotes: 0
Views: 176
Reputation: 194
Well, I must admit that my original question was not precise. It turned out that the application I was searching for was listed by Process32First / Process32Next; however, the challenge was to find it by its name.
Here is my final code for those who might face a similar situation.
procedure KillUnwantedApp;
type
PEnumInfo = ^TEnumInfo;
TEnumInfo = record
PID: DWORD;
WindowTitle: string;
end;
var FHandle : THandle;
Process : TProcessEntry32;
Next : Boolean;
function EnumWindowsProc(Wnd: HWND; Info: PEnumInfo): BOOL; stdcall;
var WindowPID: DWORD;
Title: array[0..255] of Char;
begin
Result := True;
GetWindowThreadProcessId(Wnd, @WindowPID);
if WindowPID = Info^.PID then
begin
if GetWindowText(Wnd, Title, SizeOf(Title)) > 0 then
begin
Info^.WindowTitle := Title;
Result := False;
end;
end;
end;
function GetWindowTitleFromPID(PID: DWORD): string;
var Info: TEnumInfo;
begin
Info.PID := PID;
Info.WindowTitle := '';
EnumWindows(@EnumWindowsProc, LPARAM(@Info));
Result := Info.WindowTitle;
end;
function TerminateProcessByPID(PID: DWORD; ExitCode: DWORD = 0): Boolean;
var hProcess: THandle;
begin
Result := False;
hProcess := OpenProcess(PROCESS_TERMINATE, False, PID);
if hProcess <> 0 then
begin
try
Result := TerminateProcess(hProcess, ExitCode);
finally
CloseHandle(hProcess);
end;
end;
end;
begin
FHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
Process.dwSize := Sizeof(Process);
Next := Process32First(FHandle, Process);
while Next do
begin
if pos('searched_application_name', GetWindowTitleFromPID(Process.th32ProcessID)) > 0 then
TerminateProcessByPID(Process.th32ProcessID);
Next := Process32Next(FHandle,Process);
end;
CloseHandle(FHandle);
end;
Upvotes: 0