2

我想使用Delphi代码启动一个程序,并“命令”它执行一个操作,在这种情况下是一个按钮单击。

我知道您可以使用命令行启动程序,但我需要正确的参数来单击按钮。我如何或在哪里可以找到它?

4

7 回答 7

9

您可以使用像AutoIt这样的专为自动化 GUI 应用程序而设计的程序。例如,AutoIt 可以运行一个程序,等待该程序的窗口完成加载,然后模拟该窗口中的按钮单击。

这远非理想情况——命令行参数或 COM 互操作更可靠——但它确实有效。

AutoIt 也可以作为 COM 或 DLL 版本使用,因此您可以直接从 Delphi 应用程序中使用它。

于 2009-10-15T16:07:30.163 回答
3

我编写了以下单元以更健壮的方式解析命令行参数。随意使用它。我在单位之后包含了一个示例用法(滚动到底部)。

unit CLArgParser;
//this class makes it easier to parse command line arguments
interface

uses
  Classes;

type
  strarr = array of string;

type
  TCLArgParser = class
  private
    FPermitTags : array of string;
    FTrimAll: boolean;
  public
    function IsArg(argtag : string) : boolean;
    function GetArg(argtag : string) : string;
    function GetDelimtedArg(argtag, delimiter : string) : TStringList;
    constructor Create(ArgTags : array of string); overload;
    constructor Create; overload;

    property TrimAll: boolean read FTrimAll write FTrimAll;
  end;

implementation

uses
  SysUtils;

const
  cDefaultTags : array[0..1] of string =  ('-','/');

constructor TCLArgParser.Create(ArgTags : array of string);
var i : integer;
begin
  try
    SetLength(FPermitTags,High(ArgTags)+1);
    for i := 0 to High(ArgTags) do begin
      FPermitTags[i] := ArgTags[i];
    end;  //for i
  except on e : exception do
    raise;
  end;  //try-except
end;

constructor TCLArgParser.Create;
begin
  FTrimAll := False;  //default value
  inherited Create;
  Create(cDefaultTags);
end;

function TCLArgParser.GetArg(argtag: string): string;
var i,j,n : integer;
begin
  try
    Result := '';
    n := High(FPermitTags);

    for i := 1 to ParamCount do
      for j := 0 to n do
        if Uppercase(ParamStr(i)) = (FPermitTags[j] + Uppercase(argtag)) then
          Result := ParamStr(i+1);

    if FTrimAll then begin
      Result := Trim(Result);
    end;
  except on e : exception do
    raise;
  end;  //try-except
end;

function TCLArgParser.GetDelimtedArg(argtag, delimiter: string): TStringList;
var i : integer;
    argval, tmp : string;
begin
  try
    Result := TStringList.Create;
    argval := GetArg(argtag);

    for i := 1 to Length(argval) do begin
      if ((i = Length(argval)) or ((argval[i] = delimiter) and (tmp <> '')))
      then begin
        if i = Length(argval) then begin
          tmp := tmp + argval[i];
          if FTrimAll then begin
            tmp := Trim(tmp);
          end;
        end;
        Result.Add(tmp);
        tmp := '';
      end  //if we found a delimted value
      else begin
        tmp := tmp + argval[i];
      end;  //else we just keep looking
    end;  //for ea. character

  except on e : exception do
    raise;
  end;  //try-except
end;

function TCLArgParser.IsArg(argtag: string): boolean;
var i,j,n : integer;
begin
  try
    Result := False;
    n := High(FPermitTags);

    for i := 1 to ParamCount do begin
      for j := 0 to n do begin
        if Uppercase(ParamStr(i)) = (FPermitTags[j] + Uppercase(argtag))
        then begin
          Result := True;
          Exit;
        end;  //if we found it
      end;  //for j
    end;  //for i
  except on e : exception do
    raise;
  end;  //try-except
end;

end.

示例用法:

procedure DefineParameters;
var
  clarg: TCLArgParser;
begin
  //assign command line arguments to various global variables
  clarg := TCLArgParser.Create;
  try
    wantshelp := clarg.IsArg('?') or clArg.IsArg('help');

    dbuser := clarg.GetArg('u');
    dbpwd := clarg.GetArg('p');
    dbserver := clarg.GetArg('d');

    localfilename := clarg.GetArg('localfile');

    ftpuser := clarg.GetArg('ftu');
    ftppwd := clarg.GetArg('ftp');
    ftpipaddr := clarg.GetArg('fti');

    emailfromacct := clarg.GetArg('efrom');
    emailtoacct := clarg.GetArg('eto');

    archivefolder := clarg.GetArg('archive');
    if archivefolder <> '' then begin
      if archivefolder[Length(archivefolder)] <> '\' then begin
        archivefolder := archivefolder + '\';
      end;
    end;

    //figure out the (optional) verbosity code.
    //if they didn't specify, assume the default value
    verbosity := c_VerbosityDefault;
    if clArg.IsArg('v') then begin
      if not(TryStrToInt(clarg.GetArg('v'),verbosity)) then begin
        WriteLn('Invalid verbosity code- using default of ' +
          IntToStr(c_VerbosityDefault) + '.');
      end;  //if their specified verbosity was invalid
    end;  //if they specified the verbosity

    if not(TryStrToInt(clarg.GetArg('maxtime'),maxtime)) then begin
      maxtime := 9999999;
    end;
  finally
    FreeAndNil(clarg);
  end;  //try-finally
end;
于 2009-10-15T17:00:03.040 回答
3

远程控制另一个应用程序是可能的,但是对于更高版本的 Windows (Vista/Win7),它只有在您正在控制的程序和您的程序在同一进程级别上运行时才能工作。(例如,两个应用程序都没有以管理员身份运行)。您要做的是使用 FindWindow api 找到按钮的窗口句柄,然后将适当的鼠标消息发送到您找到的句柄。因为不同的应用程序行为不同,这将需要一些实验来获得正确的消息传递。我相信 WM_MOUSEDOWN 和 WM_MOUSEUP 通常是您想要发送的。

于 2009-10-15T16:19:32.103 回答
2

您需要了解的是程序如何获知按钮单击。为此,您可以使用 Delphi 附带的 WinSight 或(更好的)Spy++。您运行程序,开始使用这些工具之一收听消息,单击按钮,看看会发生什么。很可能,您会对 WM_COMMAND 消息感兴趣(您可以过滤掉所有其他消息,以减少 Spy++ 中的信息量)。检查单击按钮时发生的情况,哪些值存储在 WM_COMMAND 消息的 wParam 和 lParam 中。从 Spy++ 中读取程序窗口的类和/或标题,并在应用程序的 FindWindow 中使用它。然后,使用 SendMessage 将检测到的消息及其参数发送到获得的窗口句柄,然后你就走了:) 有时,消息不是 WM_COMMAND,而是其他东西,

于 2009-10-15T21:37:48.893 回答
1

自动化可能是适合您的工具。也可以编写代码,但只需单击一个按钮,它可能太复杂了。

于 2009-10-15T16:42:23.827 回答
1

Delphi 提供了 2 个全局变量供您选择参数:ParamCount 和 ParamStr。

ParamStr(0) 始终是正在运行的可执行文件的完整路径和文件名。

从那时起,由您决定参数是什么。因此,如果您希望将参数称为“clickbutton”,请在 .dpr 文件中的 Application.Run 之前执行以下操作:

var
  i: Integer;

for i := 0 to ParamCount Do
 if (Lowercase(ParamStr(i)) = 'clickbutton') then
  Form1.Button1.Click;

那么如果你的项目是用命令行调用的:

 project1.exe clickbutton

然后将在 Form1 上单击 Button1。

于 2009-10-15T14:05:39.193 回答
0

查看AutoHotKey。它允许您对按键进行编程。它是免费的、开源的、轻量级的和可编程的。它得到了用户社区的大力支持,并且有几个有用的实用程序。在Lifehacker 网站上有一些可以用它来完成的例子。

于 2009-10-15T17:35:00.303 回答