当前,我正在Delphi中创建一个应用程序,它将在关闭打开的应用程序后完全关闭计算机的电源。目前,我遇到的问题是代码在Win10企业版中无法正常运行,并且正在注销用户,但没有完全关闭PC。代码的头脑在下面,我不清楚为什么这只会让我登出,而没有完全关闭计算机。
用户将定义要通过CMD运行的参数,以关闭引用该应用程序的计算机。该应用程序将关闭打开的进程,并通过CMD传递关闭进程。
procedure TfrmCleanShutdown.ProcessCommandLine;
const
CMD_CAPTION = 'w'; // window capShuttion
CMD_CLASSNAME = 'c'; // window class name
CMD_ACTION = 'a';
CMD_TIMEOUT = 't';
S_SHUTDOWN = 'shutdown';
S_LOGOFF = 'logoff';
S_RESTART = 'restart';
var
cmdl: TCommandLineParameterList;
cmd: TCommandLineParameter;
begin
cmdl := TCommandLineParameterList.Create;
cmdl.Initialize;
cmd := cmdl.FindByParam(CMD_CAPTION);
if Assigned(cmd) then
FWaitForWindowCaption := cmd.Param
else
FWaitForWindowCaption := '';
cmd := cmdl.FindByParam(CMD_CLASSNAME);
if Assigned(cmd) then
FWaitForWindowClassName := cmd.Param
else
FWaitForWindowClassName := '';
cmd := cmdl.FindByParam(CMD_TIMEOUT);
if Assigned(cmd) then
FTimeout := StrToIntDef(cmd.Param, DEF_TIMEOUT)
else
FTimeout := DEF_TIMEOUT;
FAction := EWX_LOGOFF or EWX_FORCEIFHUNG; // default action
cmd := cmdl.FindByParam(CMD_ACTION);
if Assigned(cmd) then begin
if cmd.Param = S_SHUTDOWN then
FAction := EWX_POWEROFF or EWX_FORCEIFHUNG
else if cmd.Param = S_RESTART then
FAction := EWX_REBOOT or EWX_FORCEIFHUNG
end;
end;
procedure TfrmCleanShutDown.ThreadTerminate(Sender: TObject);
begin
if (Sender as TWaitForWindowCloseThread).Success then
ExitWindowsEx(FAction, 0)
else
Label1.Caption := 'Timeout';
end;
任何帮助将不胜感激。我不清楚为什么win10会以一种方式注销用户而不是关闭用户,因为该应用程序是通过CMD运行的,并且用户具有关闭用户的权限。这非常令人困惑。
从下面的注释中添加命令行代码。
unit uCommandLine;
interface
uses
SysUtils, Classes, Contnrs;
const
S_SWITCHES = '+-*';
type
//======================================
// TCommandLineParameter
//======================================
TCommandLineParameter = class
private
FParam: String;
FSwitch: String;
FOptions: String;
public
property Param: String read FParam write FParam;
property Switch: String read FSwitch write FSwitch;
property Options: String read FOptions write FOptions;
end; // TCommandLineParameter
//======================================
// TCommandLineParameterList
//======================================
TCommandLineParameterList = class(TObjectList)
private
function GetParameter(idx: Integer): TCommandLineParameter;
public
function Initialize: Boolean;
function FindByParam(const ParamString: String): TCommandLineParameter;
property Parameters[idx: Integer]: TCommandLineParameter read GetParameter;
end;
implementation
const
C_CMD_DELIM: Char = '-';
//======================================
// TCommandLineParameter
//======================================
//======================================
// TCommandLineParameterList
//======================================
//------------------------------------------------------------------------------
function TCommandLineParameterList.GetParameter(idx: Integer): TCommandLineParameter;
begin
Result := TCommandLineParameter(Items[idx]);
end;
//------------------------------------------------------------------------------
function TCommandLineParameterList.Initialize: Boolean;
var
n, idx: Integer;
p: TCommandLineParameter;
s: String;
begin
Result := True;
p := nil;
n := ParamCount;
for idx := 1 to n do begin
s := Trim(ParamStr(idx));
if s[1] = C_CMD_DELIM then begin
System.Delete(s, 1, 1);
p := FindByParam(s);
if p = nil then begin
p := TCommandLineParameter.Create;
p.Param := s;
Add(p);
end
else begin
Result := False;
break;
end;
end
else begin
if p <> nil then begin
p.Options := s;
p := nil;
end
else begin
Result := False;
break;
end;
end;
end;
end;
//------------------------------------------------------------------------------
function TCommandLineParameterList.FindByParam(const ParamString: String): TCommandLineParameter;
var
idx: Integer;
begin
Result := nil;
for idx := 0 to Count-1 do
if CompareStr(Parameters[idx].Param, ParamString) = 0 then begin
Result := Parameters[idx];
break;
end;
end;
end.
您没有正确处理命令行参数。
使用命令行时:
-w -a shutdown -t 45
FindByParam(CMD_ACTION)
返回其TCommandLineParameter
为Param
且'a'
为Options
的'shutdown'
。但是您正在'shutdown'
中寻找Param
,而不是Options
。
同样,您最终使用ExitWindowsEx()
标志而不是EWX_LOGOFF
标志。
如果调试了代码,您会看到这种情况。
您在所有命令中都犯了相同的错误。
改用它:
EWX_POWEROFF
话虽如此,您的procedure TfrmCleanShutdown.ProcessCommandLine;
const
CMD_CAPTION = 'w'; // window capShuttion
CMD_CLASSNAME = 'c'; // window class name
CMD_ACTION = 'a';
CMD_TIMEOUT = 't';
S_SHUTDOWN = 'shutdown';
S_LOGOFF = 'logoff';
S_RESTART = 'restart';
var
cmdl: TCommandLineParameterList;
cmd: TCommandLineParameter;
begin
cmdl := TCommandLineParameterList.Create;
try
cmdl.Initialize;
cmd := cmdl.FindByParam(CMD_CAPTION);
if Assigned(cmd) then
FWaitForWindowCaption := cmd.Options
else
FWaitForWindowCaption := '';
cmd := cmdl.FindByParam(CMD_CLASSNAME);
if Assigned(cmd) then
FWaitForWindowClassName := cmd.Options
else
FWaitForWindowClassName := '';
cmd := cmdl.FindByParam(CMD_TIMEOUT);
if Assigned(cmd) then
FTimeout := StrToIntDef(cmd.Options, DEF_TIMEOUT)
else
FTimeout := DEF_TIMEOUT;
FAction := EWX_LOGOFF or EWX_FORCEIFHUNG; // default action
cmd := cmdl.FindByParam(CMD_ACTION);
if Assigned(cmd) then
begin
if cmd.Options = S_SHUTDOWN then
FAction := EWX_POWEROFF or EWX_FORCEIFHUNG
else if cmd.Options = S_RESTART then
FAction := EWX_REBOOT or EWX_FORCEIFHUNG
end;
finally
cmdl.Free;
end;
end;
是完全多余的,可以删除,因为RTL的TCommandLineParameterList
函数可以为您完成所有相同的工作,例如:
SysUtils.FindCmdLineSwitch()