Is possible hook EnumWindowsProc callback function? - delphi

I want know if is possible hook a callback function for example like EnumWindowsProc() using inline hook approach? and if yes, could provide a code snippet (example) please?
Thank you.
EDITION:
EnumWindowsProc is a callback implemented in other app. I not call it inside my app.
And i want hook EnumWindowsProc in this other app, by dll injection.

You have to handle EnumWindows at first, then you have to replace pointer to original EnumWindowsProc to yourself.
My example is valid fow win32
unit Patch;
interface
procedure PatchEnumWindows(Patch: Boolean);
implementation
uses SysUtils, SyncObjs, Windows;
const
INSTR_SIZE = 6;
var
OldEnumWindows: array [0..INSTR_SIZE-1] of Byte;
EnumWindowsPatched: Boolean = False;
function PatchedEnumWindows(EnumWindowsProc: Pointer; Param: Pointer); stdcall;
begin
// You have to replace original EnumWindowsProc to yourself
end;
procedure ApiRedirect(OrigFunction, NewFunction: Pointer; var Old);
const
TEMP_JMP: array[0..INSTR_SIZE-1] of Byte = ($E9,$90,$90,$90,$90,$C3);
var
JmpSize: DWORD;
JMP: array [0..INSTR_SIZE-1] of Byte;
OldProtect: DWORD;
begin
Move(TEMP_JMP, JMP, INSTR_SIZE);
JmpSize := DWORD(NewFunction) - DWORD(OrigFunction) - 5;
if not VirtualProtect(LPVOID(OrigFunction), INSTR_SIZE, PAGE_EXECUTE_READWRITE, OldProtect) then
raise Exception.CreateFmt('%s', [SysErrorMessage(GetLastError)]);
Move(OrigFunction^, Old, INSTR_SIZE);
Move(JmpSize, JMP[1], 4);
Move(JMP, OrigFunction^, INSTR_SIZE);
VirtualProtect(LPVOID(OrigFunction), INSTR_SIZE, OldProtect, nil);
end;
procedure PatchEnumWindows(Patch: Boolean);
var
OrigEnumWindows: Pointer;
begin
if Patch <> EnumWindowsProcPatched then begin
OrigEnumWindows := GetProcAddress(GetModuleHandle('user32.dll'), 'EnumWindows');
if Patch then begin
ApiRedirect(OrigEnumWindows, #PatchedEnumWindows, OldEnumWindows);
end
else begin
Move(OldEnumWindows, OrigEnumWindows, INSTR_SIZE);
end;
EnumWindowsPatched := Patch;
end;
end;
end.

Related

Creating and connecting DirectShow filter: how to implement CreateInstance()?

I want to write my own DirectShow filter to pull out packets of information for my own purposes. To do this, I used the guide to creating filters.
I did steps 1 to 5, and am stuck at step 6: failed to implement CreateInstance(). Can't instantiate the class because the MSDN example doesn't pass parameters, but code in Pascal requires (ObjectName: string; unk: IUnKnown; const clsid: TGUID). I used regsvr32, unfortunately I don’t know how to connect my DLL and I can’t think of it. The DSFMgr program also does not see my filter.
I read how filters are connected, tried to implement various searches, it's useless. Tried to connect manually via CLSID. Everything is useless. I know the answer is somewhere on the surface, but I don't see it. I can't figure out how DirectShow should see my library if it didn't exist in the first place. It's not logical. I've been trying to implement this for a very long time, but it doesn't work, I'm stuck.
Please don't recommend FFmpeg and the like. I don't want to use third party libraries. In DirectX, as far as I know it's built-in.
Step 6 example:
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
I Implemented/converted it like this, but it doesn't work. Errors:
no variables sent
function TCRleFilter.CreateInstance(pUnk: PPUnknown; pHr: HRESULT): PUnknown;
var
pFilter: TCRleFilter;
begin
pFilter:= TCRleFilter.Create();
if pFilter = nil then pHr:= E_OUTOFMEMORY;
Result:= pFilter;
end;
I think at least a logical explanation should suffice.
The whole class:
unit Unit1;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, ActiveX, Classes, ComObj, DirectShow9, BaseClass, Dialogs;
type
TCRleFilter = class(TBCTransformFilter)
public
function CheckInputType(mtIn: PAMMediaType): HRESULT;
function GetMediaType (IPosition: Integer; pMediaType: PAMMediaType): HRESULT;
function CheckTransform(mtln: PAMMediaType; mt0ut: PAMMediaType): HRESULT;
function DecideBufferSize(pAlloc: IMemAllocator; pProp: PAllocatorProperties): HRESULT;
function Transform(pSource, pDest: IMediaSample): HRESULT;
function CreateInstance(pUnk: PPUnknown; pHr: HRESULT): PUnknown;
end;
const
CLSID_CRleFilter: TGUID = '{FBA9B97F-505B-49C7-A6C2-D1EFC34B2C0D}';
implementation
uses ComServ;
{ TCRleFilter }
function TCRleFilter.CheckInputType(mtIn: PAMMediaType): HRESULT;
begin
Result := S_OK;
ShowMessage('CheckInputType: âåðíóë "S_OK"');
end;
function TCRleFilter.CheckTransform(mtln, mt0ut: PAMMediaType): HRESULT;
begin
Result := S_OK;
ShowMessage('CheckTransform: âåðíóë "S_OK"');
end;
function TCRleFilter.CreateInstance(pUnk: PPUnknown;
pHr: HRESULT): PUnknown;
var
pFilter: TCRleFilter;
begin
try
pFilter:= TCRleFilter.Create('');
Result := pFilter;
except
pHr:= E_OUTOFMEMORY;
Result:= nil;
end;
end;
function TCRleFilter.DecideBufferSize(pAlloc: IMemAllocator; pProp: PAllocatorProperties): HRESULT;
begin
Result := S_OK;
ShowMessage('DecideBufferSize: âåðíóë "S_OK"');
end;
function TCRleFilter.GetMediaType(IPosition: Integer; pMediaType: PAMMediaType): HRESULT;
begin
Result := S_OK;
ShowMessage('GetMediaType: âåðíóë "S_OK"');
end;
function TCRleFilter.Transform(pSource, pDest: IMediaSample): HRESULT;
begin
Result := S_OK;
ShowMessage('Transform: âåðíóë "S_OK"');
end;
initialization
{.Create(ComServer, TCRleFilter, Class_CRleFilter, 'CRleFilter', 'CRle_Filter', ciMultiInstance, tmApartment); }
TBCClassFactory.CreateFilter(TCRleFilter,'CRle_Filter', CLSID_CRleFilter, CLSID_LegacyAmFilterCategory, MERIT_DO_NOT_USE, 0, nil );
end.
Your class inherites from TBCTransformFilter and the needed parameters are defined as:
constructor TBCTransformFilter.Create(ObjectName: string; unk: IUnKnown; const clsid: TGUID);
Untested, but it should be much more correct than your attempt:
function TCRleFilter.CreateInstance
( pUnk: IUnknown // LPUNKNOWN
; var pHr: HRESULT // Pointer to variable = VAR
): PUnknown; // Pointer
var
oFilter: TCRleFilter; // Object, not pointer
begin
try // Failing constructors throw exceptions
oFilter:= TCRleFilter.Create( 'my RLE encoder', pUnk, CLSID_CRleFilter );
result:= oFilter; // In doubt cast via "PUnknown(oFilter)"
except // Constructor failed, oFilter is undefined
pHr:= E_OUTOFMEMORY;
result:= nil;
end;
end;
The var parameter ensures that assigned values inside the function also live on outside the function - otherwise you'd only have a local variable. Which is also the point (haha) of pointers in C++ parameters.

Delphi Pointers, Arrays, Handles

I can't get my head around pointers using a custom record and making array of records then a pointer to that record, specifically what I want to achieve is to make a record for each top level window handle with the given classname, meaning there is more than 1, for each window I use EnumChildWindow to obtain handles to child windows with in. I wanted to make record of each of these and pass it to a combobox with title and make the record an object of that item so I can access each recorded later on via selecting it.
My problem is my handling of pointers, I keep getting access denied on the first instance of adding any to one of the array records.
Breaks here
Param[Form1.iEnumWin].MainHwnd:= aHwnd;
here is the full code I am using so people can get a better understanding on what I am trying to do.
implementation
{$R *.dfm}
type
TMyEnumParam = record
sTitle: String;
MainHwnd: Hwnd;
InTxtHwnd: Hwnd;
OutTxtHwnd: Hwnd;
NickListHwnd: Hwnd;
end;
PMyEnumParam = ^TMyEnumParam;
type
ATMyEnumParam = Array[0..9] of PMyEnumParam;
PATMyEnumParam = ^ATMyEnumParam;
{ Get the window Title based on Hwnd }
function GetWindowTitle(HWND: HWND): string;
begin
SetLength(Result, 255);
SetLength(Result, GetWindowText(HWND, PChar(Result), 255));
end;
{ Get the Classname based on Hwnd }
function GetWindowClass(HWND: HWND): string;
begin
SetLength(Result, 255);
SetLength(Result, GetClassName(HWND, PChar(Result), 255));
end;
{ EnumChildWidows Callback Add to our records }
Function EnumChildProc(aHwnd: Hwnd; Param: PMyEnumParam): Boolean; stdcall;
begin
if ((GetDlgCtrlID(aHwnd) = 202) and (isWindowVisible(aHwnd) = True)) then
Param.InTxtHwnd:= aHwnd;
if ((GetDlgCtrlID(aHwnd) = 203) and (isWindowVisible(aHwnd) = True)) then
Param.OutTxtHwnd:= aHwnd;
if ((GetDlgCtrlID(aHwnd) = 1789) and (isWindowVisible(aHwnd) = True)) then
Param.NickListHwnd:= aHwnd;
Result:= True;
end;
{ EnumWindow fill our array of records for each window }
function EnumWindowsProc(aHwnd: HWND; Param: PATMyEnumParam): BOOL; stdcall;
begin
Result := True;
if GetWindowClass(aHwnd) = 'DlgGroupChat Window Class' then
begin
Param[Form1.iEnumWin].MainHwnd:= aHwnd;
Param[Form1.iEnumWin].sTitle:= GetWindowTitle(aHwnd);
EnumChildWindows(aHwnd, #EnumChildProc, LParam(#Param[Form1.iEnumWin]));
Form1.cbbRooms.AddItem(Param[Form1.iEnumWin].sTitle, TObject(Param[form1.iEnumWin]));
inc(Form1.iEnumWin);
end;
end;
{ On change display room Title for each item }
procedure TForm1.cbbRoomsChange(Sender: TObject);
var
i: Integer;
aHwnd: PMyEnumParam;
begin
i := cbbRooms.ItemIndex;
if cbbRooms.ItemIndex <> -1 then
begin
aHwnd:= PMyEnumParam(cbbRooms.Items.Objects[i]);
if aHwnd.MainHwnd > 0 then
begin
ShowMessage(aHwnd.sTitle);
end;
end;
end;
{ Call EnumWindows and fill our array records }
procedure TForm1.FormCreate(Sender: TObject);
var
arInfo: PATMyEnumParam;
begin
iEnumWin:= 0;
EnumWindows(#EnumWindowsProc, LParam(#arInfo));
end;
Please if anyone can point (no pun intended) me in the right direction I would be grateful.
There are many things wrong with your code. Here's a non-exhaustive list:
You don't allocate any storage for your arrays.2
You pass ^PATMyEnumParam to EnumWindows which you then cast to PATMyEnumParam in the callback.
Your arrays are fixed length and you make no attempt to handle out of bounds access to the arrays.
But your biggest problem is that your code is attempting to run before you can walk. It has full complexity and all the functionality that you need. Yet you cannot yet manage to make a single successful call to EnumWindows.
My biggest piece of advice here is not in the detail, but the generality of problem solving. Start by writing a simple piece of code. Understand it. Then enhance it.
So, in that vein, here is how to make a call to EnumerateWindows:
program EnumWindowsDemo_17620346;
{$APPTYPE CONSOLE}
uses
System.SysUtils, Winapi.Windows, Generics.Collections;
type
TWindowInfo = record
Handle: HWND;
// expand with more fields in due course
end;
function EnumWindowProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
WindowList: TList<TWindowInfo>;
WindowInfo: TWindowInfo;
begin
WindowList := TList<TWindowInfo>(lParam);
WindowInfo.Handle := hwnd;
WindowList.Add(WindowInfo);
Result := True;
end;
procedure Main;
var
WindowList: TList<TWindowInfo>;
WindowInfo: TWindowInfo;
begin
WindowList := TList<TWindowInfo>.Create;
try
EnumWindows(#EnumWindowProc, LPARAM(WindowList));
for WindowInfo in WindowList do
Writeln(WindowInfo.Handle);
finally
WindowList.Free;
end;
end;
begin
Main;
Readln;
end.
Starting from here you can expand this concept, because all the tricky parts are already taken care of. Specifically the pointer, casting and memory management.

Enumerate global methods of a unit using delphi

suppose i have a unit like this
unit sample;
interface
function Test1:Integer;
procedure Test2;
implementation
function Test1:Integer;
begin
result:=0;
end;
procedure Test2;
begin
end;
end.
Is possible enumerate all the procedures and functions of the unit sample in runtime?
No. RTTI is not generated for standalone methods. Hopefully this will be fixed in a later version, (they'd probably need a TRttiUnit type to do that,) but for now it's not available.
You could extract that information from some kind of debug info (TD32, Map file, Jdbg, etc.) using JCL and their great JclDebug.pas.
Try this:
uses
JclDebug;
type
TProc = record
name: string;
addr: Pointer;
end;
TProcArray = array of TProc;
TMapLoader = class
private
FModule: Cardinal;
FProcs: TProcArray;
FMapFileName: string;
FUnitName: string;
procedure HandleOnPublicsByValue(Sender: TObject; const Address: TJclMapAddress; const Name: string);
public
constructor Create(const AFileName: string; AModule: Cardinal; const AUnitName: string);
procedure Scan();
property Procs: TProcArray read FProcs;
end;
constructor TMapLoader.Create(const AFileName: string; AModule: Cardinal; const AUnitName: string);
begin
inherited Create;
FMapFileName := AFileName;
FModule := AModule;
FUnitName := AUnitName;
end;
procedure TMapLoader.HandleOnPublicsByValue(Sender: TObject; const Address: TJclMapAddress; const Name: string);
var
l: Integer;
begin
if Pos(FUnitName + '.', Name) = 1 then
begin
l := Length(FProcs);
SetLength(FProcs, l + 1);
FProcs[l].name := Name;
FProcs[l].addr := Pointer(Address.Offset + FModule + $1000);
end;
end;
procedure TMapLoader.Scan();
var
parser: TJclMapParser;
begin
parser := TJclMapParser.Create(FMapFileName, FModule);
try
parser.OnPublicsByValue := HandleOnPublicsByValue;
parser.Parse;
finally
parser.Free;
end;
end;
I don't think so.
That is a compile-time config, it's used so as the compiler knows which function name is being called or not. As far as I know, there is nothing at runtime which comes close to listing these functions.
Delphi's excellent runtime features come from RTTI, you might want to see what it offers in relation to this. But as I said, I don't think it's possible (know that I've delved in RTTI for quite some time...).
Edit: Oh and by the way, after compilation, functions lose their human-readable names (to addresses). There are some tables which pinpoint those names to addresses, most notably, RTTI and the Debug info.

Enumerate running processes in Delphi

How do I get a list of the running processes (with details of PID, Owner etc) on my machine using Delphi?
EDIT: None of the solutions proposed gives me the user that owns the process, only info such as PID, ExeName etc...
One way is using the Tool Help library (see TlHelp32 unit), or EnumProcesses on Windows NT (see PsAPI unit). Have a look at JclSysInfo.RunningProcessesList in the JCL for an example.
Here's a quick example of how to get the user name of a process:
type
PTokenUser = ^TTokenUser;
TTokenUser = packed record
User: SID_AND_ATTRIBUTES;
end;
function GetProcessUserName(ProcessID: Cardinal; out DomainName, UserName: string): Boolean;
var
ProcessHandle, ProcessToken: THandle;
InfoSize, UserNameSize, DomainNameSize: Cardinal;
User: PTokenUser;
Use: SID_NAME_USE;
_DomainName, _UserName: array[0..255] of Char;
begin
Result := False;
DomainName := '';
UserName := '';
ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessID);
if ProcessHandle = 0 then
Exit;
try
if not OpenProcessToken(ProcessHandle, TOKEN_QUERY, ProcessToken) then
Exit;
try
GetTokenInformation(ProcessToken, TokenUser, nil, 0, InfoSize);
User := AllocMem(InfoSize * 2);
try
if GetTokenInformation(ProcessToken, TokenUser, User, InfoSize * 2, InfoSize) then
begin
DomainNameSize := SizeOf(_DomainName);
UserNameSize := SizeOf(_UserName);
Result := LookupAccountSid(nil, User^.User.Sid, _UserName, UserNameSize, _DomainName, DomainNameSize, Use);
if Result then
begin
SetString(DomainName, _DomainName, StrLen(_DomainName));
SetString(UserName, _UserName, StrLen(_UserName));
end;
end;
finally
FreeMem(User);
end;
finally
CloseHandle(ProcessToken);
end;
finally
CloseHandle(ProcessHandle);
end;
end;
This is the function we use to check if a process exists, the FProcessEntry32 holds all the info on the process, so you should be able to extend it to what every you need.
it was taken from here
uses TlHelp32
function processExists(exeFileName: string): Boolean;
{description checks if the process is running
URL: http://www.swissdelphicenter.ch/torry/showcode.php?id=2554}
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
Result := False;
while Integer(ContinueLoop) <> 0 do
begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeFileName))) then
begin
Result := True;
end;
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
The TProcessEntry32 record looks like so:
tagPROCESSENTRY32 = packed record
dwSize: DWORD;
cntUsage: DWORD;
th32ProcessID: DWORD; // this process
th32DefaultHeapID: DWORD;
th32ModuleID: DWORD; // associated exe
cntThreads: DWORD;
th32ParentProcessID: DWORD; // this process's parent process
pcPriClassBase: Longint; // Base priority of process's threads
dwFlags: DWORD;
szExeFile: array[0..MAX_PATH - 1] of Char;// Path
end;
You have to use:
CreateToolhelp32Snapshot Function
Process32First Function
Process32Next Function
PROCESSENTRY32 Structure will contain all the informations that you may need.
The documentation is from MDSN, for C++, but it's the same in Delphi.
This class will give you a list of all open windows (listed below) with PID, caption, dimensions, etc. It's not exactly running processes information, but I've used it to find apps via it.
// Window List Component 1.5 by Jerry Ryle
//
// Aaugh! I accidentally uploaded the wrong source
// which had a nasty bug in the refresh procedure!
// Thanks to Serge, who found my mistake and suggested
// a few other improvements!
//
// This component will enumerate windows and return
// information about them in the Windows property.
// The component currently returns a handle, caption text,
// associated ProcessID, visibility, and dimensions.
// For documentation, please read the accompanying
// WindowList.txt
//
// This component is completely free of course. If you find
// it useful, and are compelled to send me cash, beer, or
// dead things in envelopes, please feel free to do so.
//
// email me if you make it better: gryle#calpoly.edu
unit WindowList;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TWindowObject = record
WinHandle : HWnd; // Window Handle
WinCaption : String; // Window Caption Text (If any)
ProcessID : Integer; // Process the window belongs to
IsVisible : Boolean; // Is the window visible?
IsEnabled : Boolean; // Is the window enabled for mouse/keyboard input?
IsIconic : Boolean; // Is the window minimized?
WindowRect : TRect; // Window Dimensions
// Add more properties here if you like,
// then fill them in at the WindowCallback
// function.
end;
PTWindowObject = ^TWindowObject;
TWindowList = class(TComponent)
private
WindowLst : TList;
FCount : Integer;
protected
Function GetAWindow(Index : Integer) : TWindowObject;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
Procedure Refresh;
Property Windows[Index : Integer]: TWindowObject read GetAWindow;
Property Count : Integer read FCount;
published
// Published declarations
end;
procedure Register;
implementation
// Note that this function is not a member of WindowList.
// Therefore, the list to be filled needs to be passed
// as a pointer. Note that this is passed as a VAR. if you
// don't do this, bad things happen in memory.
Function WindowCallback(WHandle : HWnd; Var Parm : Pointer) : Boolean; stdcall;
// This function is called once for each window
Var MyString : PChar;
MyInt : Integer;
MyWindowPtr : ^TWindowObject;
begin
New(MyWindowPtr);
// Window Handle (Passed by the enumeration)
MyWindowPtr.WinHandle := WHandle;
// Window text
MyString := Allocmem(255);
GetWindowText(WHandle,MyString,255);
MyWindowPtr.WinCaption := String(MyString);
FreeMem(MyString,255);
// Process ID
MyInt := 0;
MyWindowPtr.ProcessID := GetWindowThreadProcessId(WHandle,#MyInt);
// Visiblity
MyWindowPtr.IsVisible := IsWindowVisible(WHandle);
// Enabled
MyWindowPtr.IsEnabled := IsWindowEnabled(WHandle);
// Iconic
MyWindowPtr.IsIconic := IsIconic(WHandle);
// Window Dimensions
MyWindowPtr.WindowRect := Rect(0,0,0,0);
GetWindowRect(WHandle,MyWindowPtr.WindowRect);
// Add the structure to the list. Do not dereference Parm...
// once again, bad things happen.
TList(Parm).Add(MyWindowPtr);
Result := True; // Everything's okay. Continue to enumerate windows
end;
constructor TWindowList.Create(AOwner: TComponent);
var MyWindowPtr : PTWindowObject;
begin
inherited;
WindowLst := TList.Create;
// Thanks Serge, I should've done this from the start :)
// Sloppy me.
If Not ( csDesigning in ComponentState ) Then
Begin
EnumWindows(#WindowCallback,Longint(#WindowLst));
FCount := WindowLst.Count;
End
Else
FCount := 0;
end;
destructor TWindowList.Destroy;
var I : Integer;
begin
If WindowLst.Count > 0 Then
Begin
For I := 0 To (WindowLst.Count - 1) Do
Dispose(PTWindowObject(WindowLst[I]));
End;
WindowLst.Free;
inherited;
end;
procedure TWindowList.Refresh;
begin
WindowLst.Clear; {Clear the list!}
EnumWindows(#WindowCallback,Longint(#WindowLst));
FCount := WindowLst.Count;
end;
function TWindowList.GetAWindow(Index : Integer) : TWindowObject;
begin
Result := PTWindowObject(WindowLst[Index])^;
end;
procedure Register;
begin
RegisterComponents('System', [TWindowList]);
end;
end.
You could look at using the WMISet components ($69 single licence, $199 for site licence, trial version available). The TWmiProcessControl component seems to encapsulate calls to Win32_Process. They also have an example of getting a process owner.
I think Madshi madKernel could be interesting to check out.

How can I find the process id from the service name/handle in Delphi?

I have the service name for a windows service in delphi, and I know how to get the handle from that as well. What I need to do is stop a service, and if the stop fails for some reason I need to kill the process associated with the service. The problem is that I have multiple services running from the same executable, so I can't use the executable name to kill the process. This means I need the process id to kill the proper associated process. How can I get this id or some way to kill the proper process from the service name or handle?
QueryServiceStatusEx?
Please note I have only accepted this solution so that a full delphi code solution is accepted, all due thanks to Jk though for pointing me on the correct path.
--
Ok, I've been able to figure out how to use the answer by Jk and have come up with this solution in delphi.
For reference, this is the link provided by Jk:
QueryServiceStatusEx
My Solution:
unit Demo;
interface
uses
Windows, Forms, SysUtils,
StdCtrls, WinSvc, Controls, Classes;
type
//Form for basic demo usage
TForm6 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
end;
//Record defined for use as return buffer
_SERVICE_STATUS_PROCESS = record
dwServiceType: DWORD;
dwCurrentState: DWORD;
dwControlsAccepted: DWORD;
dwWin32ExitCode: DWORD;
dwServiceSpecificExitCode: DWORD;
dwCheckPoint: DWORD;
dwWaitHint: DWORD;
dwProcessId: DWORD;
dwServiceFlags: DWORD;
end;
//Function Prototype
function QueryServiceStatusEx(
SC_HANDLE: SC_Handle;
SC_STATUS_TYPE: Cardinal;
out lpBuffer: _SERVICE_STATUS_PROCESS;
cbBufSize: DWORD;
out pcbBytesNeeded: LPDWORD
): BOOL; stdcall;
//internal setup function
function GetPid(sService: String; sMachine: String = '') : Cardinal;
var
Form6: TForm6;
implementation
{$R *.dfm}
const
// windows api library
advapi32 = 'advapi32.dll';
//define the api call
function QueryServiceStatusEx; external advapi32 name 'QueryServiceStatusEx';
//for demo usage
procedure TForm6.Button1Click(Sender: TObject);
begin
Memo1.Lines.Add(IntToStr(Integer(GetPid('Service'))))
end;
function GetPid(sService: String; sMachine: String = '') : Cardinal;
var
schm,
schs: SC_Handle;
SC_STATUS_TYPE: Cardinal;
lpBuffer: _SERVICE_STATUS_PROCESS;
cbBufSize: DWORD;
pcbBytesNeeded: LPDWORD;
begin
//open the service manager (defined in WinSvc)
schm := OpenSCManager(PChar(sMachine), nil, SC_MANAGER_CONNECT);
//set the status type to SC_STATUS_PROCESS_INFO
//this is currently the only value supported
SC_STATUS_TYPE := $00000000;
//set the buffer size to the size of the record
cbBufSize := sizeof(_SERVICE_STATUS_PROCESS);
if (schm>0) then
begin
//grab the service handle
schs := OpenService(schm, PChar(sService), SERVICE_QUERY_STATUS);
if (schs>0) then
begin
//call the function
QueryServiceStatusEx(
schs,
SC_STATUS_TYPE,
lpBuffer,
cbBufSize,
pcbBytesNeeded);
CloseServiceHandle(schs);
end;
CloseServiceHandle(schm);
end;
Result := lpBuffer.dwProcessId;
end;
end.
Please note that not all external naming and other necessities are included.
Or use DSiWin32 for many useful functions, including DSiGetProcessID. This code was written by StackOverflow user (and programmer) Gabr.
Here's the function, for your own reference. It will give you what you are looking for:
//Retrieves ID of the specified process. Requires Toolhelp API.
// #returns False if ID cannot be retrieved. Check GetLastError - if it is 0, process
// doesn't exist; otherwise it contains the Win32 error code.
// #author gabr
// #since 2004-02-12
//
function DSiGetProcessID(const processName: string; var processID: DWORD): boolean;
var
hSnapshot: THandle;
procEntry: TProcessEntry32;
begin
Result := false;
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if hSnapshot = 0 then
Exit;
try
procEntry.dwSize := Sizeof(procEntry);
if not Process32First(hSnapshot, procEntry) then
Exit;
repeat
if AnsiSameText(procEntry.szExeFile, processName) then begin
processID := procEntry.th32ProcessID;
Result := true;
break; // repeat
end;
until not Process32Next(hSnapshot, procEntry);
finally DSiCloseHandleAndNull(hSnapshot); end;
end; { DSiGetProcessID }

Resources