views:

409

answers:

7

I want to start a program using Delphi code, and "command" it to perform an action, in this case a button click.

I know you can start a program using the command line, but I would need the right paramaters for the button click. How or where can I find it?

+1  A: 

Delphi provides 2 global variables for you to pick up parameters: ParamCount and ParamStr.

ParamStr(0) is always the full path and filename of the executable that is running.

From then on it is up to you what the parameters are. So if you want the parameter to be called "clickbutton", then do something like this before Application.Run in the .dpr file:

var
  i: Integer;

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

So then if your project is called with the command line:

 project1.exe clickbutton

then Button1 will be clicked on Form1.

_J_
Thanks for the quick reaction.This will work for my own written project.But my problem is that i want to command a (closed source) executable, to start and perform certain action using my own delphi program.Can i still use this to pick up parameters for the closed source software?
Makaku00
No, as Knobloch said, unless the program is designed to take parameters and perform certain tasks with them, you can't "inject" that into it. Otherwise there'd be hell to pay with all sorts of software out there.As he also said, try running the exe with the /? from the command line to see if there are any parameters that the program accepts. Otherwise, there's no way.
_J_
+8  A: 

You could use a program like AutoIt that's designed for automating GUI applications. For example, AutoIt can run a program, wait for that program's window to finish loading, then simulate a button click in that window.

This is far from an ideal situation - command-line parameters or COM Interop are much more reliable - but it works.

AutoIt is also available as a COM or DLL version so that you can use it directly from your Delphi app.

Josh Kelley
+3  A: 

Remote controlling another application is possible, however with the later versions of Windows (Vista/Win7) it will ONLY work if the program you are controlling and your program are running in the same process level. (both apps NOT running as administrator for example). What you will want to do is to find the windows handle of the button using the FindWindow api, then send appropriate mouse messages to the handle you located. Because different applications behave differently this will require some experimentation to get the messaging correct. I believe that WM_MOUSEDOWN and WM_MOUSEUP generally are what your looking to send.

skamradt
+1  A: 

Automise might be right tool for you. It's also possible to code that, but for just one button click it might be too complicated.

Harriv
A: 

I have written the below unit to parse command line arguments in a more robust way. Feel free to use it. I've included an example usage after the unit (scroll to the bottom).

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.

Example usage:

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;
JosephStyons
A: 

Check out AutoHotKey. It allows you to program key clicks. It's free, open source, light-weight and programmable. It enjoys substantial support from its user community and there are several useful utilities made with it. There are some examples of what can be done with it on the Lifehacker web site.

+1  A: 

What you need to find out is how the program gets informed of the button click. For that you can use WinSight that comes with Delphi or (much better) Spy++. You run the program, start listening for messages using one of these tools, click the button and see what happens. Most likely, you'd be interested in the WM_COMMAND message (you can filter out all other messages, to reduce the amount of information in Spy++). Inspect what happens when you click the button, which values are stored in wParam and lParam of the WM_COMMAND message. Read the class and/or title of the program's window from Spy++ and use that in FindWindow in your app. Then, use SendMessage to send the detected message and its params to the obtained window handle and off you go :) Sometimes, the message is not WM_COMMAND, but something else, in which case you need to inspect more to find the right one

Dejan