我使用下面的代码获取Windows服务的列表。它适用于Delphi 10.2.3和更早版本:
uses WinSvc;
//-------------------------------------
// Get a list of services
//
// return TRUE if successful
//
// sMachine:
// machine name, ie: \SERVER
// empty = local machine
//
// dwServiceType
// SERVICE_WIN32,
// SERVICE_DRIVER or
// SERVICE_TYPE_ALL
//
// dwServiceState
// SERVICE_ACTIVE,
// SERVICE_INACTIVE or
// SERVICE_STATE_ALL
//
// slServicesList
// TStrings variable to storage
//
function ServiceGetList(
sMachine : string;
dwServiceType,
dwServiceState : DWord;
slServicesList : TStrings )
: boolean;
const
//
// assume that the total number of
// services is less than 4096.
// increase if necessary
cnMaxServices = 4096;
type
TSvcA = array[0..cnMaxServices]
of TEnumServiceStatus;
PSvcA = ^TSvcA;
var
//
// temp. use
j : integer;
//
// service control
// manager handle
schm : SC_Handle;
//
// bytes needed for the
// next buffer, if any
nBytesNeeded,
//
// number of services
nServices,
//
// pointer to the
// next unread service entry
nResumeHandle : DWord;
//
// service status array
ssa : PSvcA;
begin
Result := false;
// connect to the service
// control manager
schm := OpenSCManager(
PChar(sMachine),
Nil,
SC_MANAGER_ALL_ACCESS);
// if successful...
if(schm > 0)then
begin
nResumeHandle := 0;
New(ssa);
EnumServicesStatus(
schm,
dwServiceType,
dwServiceState,
ssa^[0],
SizeOf(ssa^),
nBytesNeeded,
nServices,
nResumeHandle );
//
// assume that our initial array
// was large enough to hold all
// entries. add code to enumerate
// if necessary.
//
for j := 0 to nServices-1 do
begin
slServicesList.
Add( StrPas(
ssa^[j].lpDisplayName ) );
end;
Result := true;
Dispose(ssa);
// close service control
// manager handle
CloseServiceHandle(schm);
end;
end;
将所有Windows服务的列表输入名为ListBox ListBox1
的
ServiceGetList( '',
SERVICE_WIN32,
SERVICE_STATE_ALL,
ListBox1.Items );
我尝试在Delphi10.4和Delphi11中使用相同的代码,但是EnumServicesStatus
函数有一个问题:
dcc32错误单位1.PAS(145):E2010不兼容类型:“LPENUM_SERVICE_STATUSW”和“_ENUM_SERVICE_STATUSW”
当我尝试LPENUM_SERVICE_STATUSW
而不是TEnumServiceStatus
时
type
TSvcA = array[0..cnMaxServices]
of LPENUM_SERVICE_STATUSW;// instead TEnumServiceStatus;
我发现了一个“访问违规”错误。
也许关键在于Winapi.WinSvc.pas
中的外部函数
function EnumServicesStatus; external advapi32 name 'EnumServicesStatusW';
发布于 2022-06-20 01:33:32
预先分配这样大的数组不是个好主意。您不能假设PC实际安装了多少服务。让EnumServicesStatus()
告诉您要为数组分配多少。
此外,您还必须考虑可能需要多次调用EnumServicesStatus()
才能获得所有状态。
现在,关于编译器问题--实际的EnumServiceStatus()
API需要一个指向ENUM_SERVICE_STATUS
记录数组(在WinSvc
单元中别名为TEnumServiceStatus
)的指针,而不是一个LPENUM_SERVICE_STATUS
指针数组。在Delphi的早期版本中,Winsvc
单元声明EnumServiceStatusW()
对数组中的第一个ENUM_SERVICE_STATUS
进行var
引用。但是很明显,它已经被重新声明,取而代之的是一个指向第一个ENUM_SERVICE_STATUS
的指针,以匹配实际的API。
所以,用这句话来说,尝试更像这样的东西:
uses
WinSvc;
{$IFDEF CONDITIONALEXPRESSIONS}
{$IF CompilerVersion >= 34}
{$DEFINE lpServices_Param_Is_Pointer}
{$IFEND}
{$ENDIF}
function ServiceGetList(
const sMachine : string;
dwServiceType,
dwServiceState : DWord;
slServicesList : TStrings )
: Boolean;
var
j : integer;
schm : SC_Handle;
nBytesNeeded,
nServices,
nResumeHandle : DWord;
buffer : array of Byte;
ssa, ss : PEnumServiceStatus;
begin
Result := False;
schm := OpenSCManager(
PChar(sMachine),
nil,
SC_MANAGER_CONNECT or SC_MANAGER_ENUMERATE_SERVICE);
if (schm <> 0) then
try
nResumeHandle := 0;
if not EnumServicesStatus(
schm,
dwServiceType,
dwServiceState,
{$IFDEF lpServices_Param_Is_Pointer}nil{$ELSE}PEnumServiceStatus(nil)^{$ENDIF},
0,
nBytesNeeded,
nServices,
nResumeHandle) then
begin
if (GetLastError() <> ERROR_INSUFFICIENT_BUFFER) and (GetLastError() <> ERROR_MORE_DATA) then
begin
Exit;
end;
SetLength(buffer, nBytesNeeded);
ssa := PEnumServiceStatus(buffer);
if not EnumServicesStatus(
schm,
dwServiceType,
dwServiceState,
ssa{$IFNDEF lpServices_Param_Is_Pointer}^{$ENDIF},
Length(buffer),
nBytesNeeded,
nServices,
nResumeHandle) then
begin
Exit;
end;
end;
if (nServices > 0) then
begin
ss := ssa;
for j := 0 to nServices-1 do
begin
slServicesList.Add(ss.lpDisplayName);
Inc(ss);
end;
end;
finally
CloseServiceHandle(schm);
end;
Result := True;
end;
https://stackoverflow.com/questions/72681375
复制相似问题