Solved

PostMessage and SendMessage for my Game

Posted on 2010-11-25
9
735 Views
Last Modified: 2012-05-10
My doubt is the following

Using PostMessage or SendMessage

How can I send a command by the Delphi example to push a button in a program at my program.

Or How tightening an arrow.

And for that I want for example:
In the game that I play GTA, I would like for example to walk with the puppet, without playing.

Save the doll and directions go alone, even attacking what he sees.


It would be something like a bot, and do not know if permitted.

But this is an offline game and I always had this doubt, for many things.
0
Comment
Question by:RevangeSMill
  • 3
  • 2
  • 2
  • +2
9 Comments
 
LVL 14

Expert Comment

by:systan
ID: 34215140
uses windows,.......
procedure TForm1.Button1Click(Sender: TObject);
begin
     EnableWindow(Form1.Button1.Handle, False);
end;

Open in new window

0
 

Author Comment

by:RevangeSMill
ID: 34215147
EnableWindow(Form1.Button1.Handle, False);

EnableWindow ?

What effect this make ?
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34215159

You need to get the window handle of the application you intend to send the message to
Use FindWindow

Then use PostMessage
Your program has to handle the messsage sent
0
Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

 
LVL 14

Expert Comment

by:systan
ID: 34215208
Oh, I though you want to disable a button, but from the other apps.
var
  DaHandle : HWND;
function GetHwnd(Handle : HWND; lParam : LPARAM) : Boolean;stdcall;
begin
  DaHandle := Handle;
  Result := True;
end;

function getwinname:string;
var
  n : array [0..MAX_PATH] of char;
begin
  if EnumThreadWindows(GetCurrentThreadId, @GetHwnd, 0) then begin
    GetWindowText(DaHandle, n, SizeOf(n));
    result := StrPas(n);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  h: HWND;
  s: array [0..MAX_PATH] of char;
begin
Form1.Caption := getwinname;
s:= Form1.Caption;
h := FindWindow(s, nil);
 if h <> 0 then
  begin
    //test
    SendMessage(h, WM_SYSCOMMAND, SC_CLOSE, 0);
  end;
end;

Open in new window

0
 
LVL 14

Expert Comment

by:systan
ID: 34215216
try to look at from this link also;
http://www.swissdelphicenter.ch/torry/showcode.php?id=327
0
 
LVL 24

Expert Comment

by:jimyX
ID: 34215229
I am not sure if I got what you are trying to do:

I would like for example to walk with the puppet, without playing
Playing games is different than using applications. You can send WM_Command to the applications' controls (not all applications though) but games you will be sending keystrokes. Sending messages to games depends on mouse position and keyboard clicks.

Save the doll and directions go alone, even attacking what he sees.
Can not be done accurately without human interference.

something like a bot
What is bot ?

Have a look on the following example from Torry. It shows couple of methods that will help you.

http://www.swissdelphicenter.ch/torry/showcode.php?id=220

You will be interested in example 3:


{3. With keybd_event API}

procedure PostKeyExHWND(hWindow: HWnd; key: Word; const shift: TShiftState;
  specialkey: Boolean);
{************************************************************
 * Procedure PostKeyEx
 *
 * Parameters:
 *  hWindow: target window to be send the keystroke
 *  key    : virtual keycode of the key to send. For printable
 *           keys this is simply the ANSI code (Ord(character)).
 *  shift  : state of the modifier keys. This is a set, so you
 *           can set several of these keys (shift, control, alt,
 *           mouse buttons) in tandem. The TShiftState type is
 *           declared in the Classes Unit.
 *  specialkey: normally this should be False. Set it to True to
 *           specify a key on the numeric keypad, for example.
 *           If this parameter is true, bit 24 of the lparam for
 *           the posted WM_KEY* messages will be set.
 * Description:
 *  This procedure sets up Windows key state array to correctly
 *  reflect the requested pattern of modifier keys and then posts
 *  a WM_KEYDOWN/WM_KEYUP message pair to the target window. Then
 *  Application.ProcessMessages is called to process the messages
 *  before the keyboard state is restored.
 * Error Conditions:
 *  May fail due to lack of memory for the two key state buffers.
 *  Will raise an exception in this case.
 * NOTE:
 *  Setting the keyboard state will not work across applications
 *  running in different memory spaces on Win32 unless AttachThreadInput
 *  is used to connect to the target thread first.
 *Created: 02/21/96 16:39:00 by P. Below
 ************************************************************}
type
  TBuffers = array [0..1] of TKeyboardState;
var
  pKeyBuffers: ^TBuffers;
  lParam: LongInt;
begin
  (* check if the target window exists *)
  if IsWindow(hWindow) then
  begin
    (* set local variables to default values *)
    pKeyBuffers := nil;
    lParam := MakeLong(0, MapVirtualKey(key, 0));

    (* modify lparam if special key requested *)
    if specialkey then
      lParam := lParam or $1000000;

    (* allocate space for the key state buffers *)
    New(pKeyBuffers);
    try
      (* Fill buffer 1 with current state so we can later restore it.
         Null out buffer 0 to get a "no key pressed" state. *)
      GetKeyboardState(pKeyBuffers^[1]);
      FillChar(pKeyBuffers^[0], SizeOf(TKeyboardState), 0);

      (* set the requested modifier keys to "down" state in the buffer*)
      if ssShift in shift then
        pKeyBuffers^[0][VK_SHIFT] := $80;
      if ssAlt in shift then
      begin
        (* Alt needs special treatment since a bit in lparam needs also be set *)
        pKeyBuffers^[0][VK_MENU] := $80;
        lParam := lParam or $20000000;
      end;
      if ssCtrl in shift then
        pKeyBuffers^[0][VK_CONTROL] := $80;
      if ssLeft in shift then
        pKeyBuffers^[0][VK_LBUTTON] := $80;
      if ssRight in shift then
        pKeyBuffers^[0][VK_RBUTTON] := $80;
      if ssMiddle in shift then
        pKeyBuffers^[0][VK_MBUTTON] := $80;

      (* make out new key state array the active key state map *)
      SetKeyboardState(pKeyBuffers^[0]);
      (* post the key messages *)
      if ssAlt in Shift then
      begin
        PostMessage(hWindow, WM_SYSKEYDOWN, key, lParam);
        PostMessage(hWindow, WM_SYSKEYUP, key, lParam or $C0000000);
      end
      else
      begin
        PostMessage(hWindow, WM_KEYDOWN, key, lParam);
        PostMessage(hWindow, WM_KEYUP, key, lParam or $C0000000);
      end;
      (* process the messages *)
      Application.ProcessMessages;

      (* restore the old key state map *)
      SetKeyboardState(pKeyBuffers^[1]);
    finally
      (* free the memory for the key state buffers *)
      if pKeyBuffers <> nil then
        Dispose(pKeyBuffers);
    end; { If }
  end;
end; { PostKeyEx }

Open in new window

0
 
LVL 25

Accepted Solution

by:
epasquier earned 500 total points
ID: 34216038
This implements the lookup of the main window using the application name (the caption of the main form), using FindWindow

it does the match with either a starting string in the window name, or a string in it, and can do that with/without case consideration.

Ex: find a window that has 'pad' in it without case sensitive :
SearchMainWindowByName( '', 'pad', True );  // Will find 'NotePad'

Var
 SearchWindowList:TStrings;

function SearchMainWindowByName(Start:String;Mid:String='';UpC:boolean=True):THandle;
type
 RR=Record
     S,M:String;
     L:integer;
     U:boolean;
     hWindow:HWND;
    end;
 pRR=^RR;
Var
 R:RR;
 function EnumProcess(hHwnd: HWND; lParam : integer): boolean; stdcall;
 var
  pPid : DWORD;
  title, ClassName : string;
  R:pRR;
 begin
  //if the returned value in null the
  //callback has failed, so set to false and exit.
  if (hHwnd=0) then result := false else
   begin
    R:=pRR(lParam);
    //additional functions to get more
    //information about a process.
    //get the Process Identification number.
{$ifdef VER140}
      GetWindowThreadProcessId(hHwnd,pPid);
{$else}
      GetWindowThreadProcessId(hHwnd,@pPid);
{$endif}
    SetLength(ClassName, 255);
    SetLength(ClassName,
              GetClassName(hHwnd,
                           PChar(className),
                           Length(className)));
    SetLength(title, 255);
    SetLength(title, GetWindowText(hHwnd, PChar(title), Length(title)));
    //Display the process information
    //by adding it to a list box
    if Assigned(SearchWindowList) Then SearchWindowList.Add
      ('Class Name = ' + className +
       '; Title = ' + title +
       '; HWND = '+ IntToStr(hHwnd) +
       '; Pid = ' + IntToStr(pPid));
    if R^.U Then title:=UpperCase(title);
    if Copy(title,1,R^.L)=R^.S Then
     begin
      if (R^.M='')
       Or (Pos(R^.M,title)>0)
        Then R^.hWindow:=hHwnd;
     end;
    Result := true;
  end;
 end;
begin
 R.hWindow:=0;
 if UpC Then
  begin
   R.S:=UpperCase(Start);
   R.M:=UpperCase(Mid);
  end Else
  begin
   R.S:=Start;
   R.M:=Mid;
  end;
 R.L:=Length(Start);
 R.U:=Upc;
 if Assigned(SearchWindowList) Then SearchWindowList.Clear;
 EnumWindows(@EnumProcess,Integer(@R));
 Result:=R.hWindow;
end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 34216068
I forgot to say :
SearchWindowList:TStrings global variable is for debuging convenience, to put in a stringlist (memo.Lines for example) all windows enumerated
initialize it to nil if you don't want to use it.

and when you found the window handle, use PostKeyExHWND as JimyX said, see add-ons below
// I personnally added some default values for the last 2 parameters of PostKeyExHWND
procedure PostKeyExHWND(hWindow: HWnd; key: Word; const shift: TShiftState=[]; specialkey: Boolean=False);

// and added a helper function to send a whole string
procedure SendStringEx (Handle : HWND; vString : String);
var
 i: integer;
begin
 for i:=1 to length(vString) do
  begin
   PostKeyExHWND(Handle,ord(vString[i]));
//   sleep(1);  // if you need some tempo between keys
  end;
end;

Open in new window

0
 

Author Closing Comment

by:RevangeSMill
ID: 34452565
This help me a partially

Thanks
0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

822 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question