 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
mibiz Cheater
Reputation: 0
Joined: 14 Jun 2009 Posts: 31
|
Posted: Wed Feb 17, 2010 1:43 pm Post subject: Pls help w/ SendKeys, SendNotifyMessage, PostMessage |
|
|
Hi,
I wrote a bot in C# using VS2005 but I'm having problem sending keys to the game. The only key that is sent successfully is the tab key. If I use AutoIt, it can send any key specified. Looking at the source code of AutoIt, it uses PostMessage and has the similar coding, in C++, to what I have in C# using p/invoke. I can't find the problem because it's not giving me any error, not even win32 error from p/invoke. Looking at the messages in Spy++, for the targeted game, both the my bot in C# and the bot in AutoIt sent the same messages to the game. Has anyone seen this kind of problem before? Or have any ideas what maybe the cause?
TIA,
/mibiz
EDIT:
My bot started with low level hooks. It couldn't send the keys, except tab key, so I thought it might be my coding or something. So I went to higher level using PostMessage & SendNotifyMessage. And finally System.Windows.Forms.SendKeys.SendWait(). All the same result. |
|
| Back to top |
|
 |
rooski Master Cheater
Reputation: 0
Joined: 31 Oct 2007 Posts: 340 Location: Siberia
|
Posted: Wed Feb 17, 2010 3:06 pm Post subject: |
|
|
| i had the same problem(forum name sendinput()) and never fixed it . one thing it could be is that the game uses direct input and does not poll the keyboard like most things do , so look into that. |
|
| Back to top |
|
 |
NINTENDO Grandmaster Cheater Supreme
Reputation: 0
Joined: 02 Nov 2007 Posts: 1371
|
Posted: Wed Feb 17, 2010 3:13 pm Post subject: |
|
|
do you have code? _________________
Intel over amd yes. |
|
| Back to top |
|
 |
mibiz Cheater
Reputation: 0
Joined: 14 Jun 2009 Posts: 31
|
Posted: Fri Feb 19, 2010 6:41 pm Post subject: |
|
|
| rooski wrote: | | i had the same problem(forum name sendinput()) and never fixed it . one thing it could be is that the game uses direct input and does not poll the keyboard like most things do , so look into that. |
That's what I thought at first too but AutoIt, using VBScript, works fine and the (underlying C++) source code for AutoIt uses PostMessage().
| JesusLovesQlimax wrote: | | do you have code? |
| Code: | [DllImport("user32.dll", CharSet= CharSet.Ansi, CallingConvention= CallingConvention.StdCall, SetLastError= true)]
internal static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern int SendNotifyMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
[DllImport("user32.dll")]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
internal static void SendKey(int pid, string key)
{
DataRow[] rows = KeysTable.Select("Key='" + key + "'");
if (rows.Length == 1)
{
int result = 0;
int wParam = (int)rows[0]["Code"];
int scanCode = (int)rows[0]["ScanCode"];
IntPtr lParamDown = new IntPtr(scanCode * 65536 + 1);
IntPtr lParamUp = new IntPtr(scanCode * 65536 + 1);
IntPtr hWnd = Process.GetProcessById(pid).MainWindowHandle;
SetForegroundWindow(hWnd);
//SendKeys.SendWait(key);
result = PostMessage(hWnd, (int)KeyboardMessagesId.WM_KEYDOWN, wParam, lParamDown);
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
Thread.Sleep(50);
result = PostMessage(hWnd, (int)KeyboardMessagesId.WM_KEYUP, wParam, lParamUp);
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
} |
That's the code I have for sending keys. Only the tab key is sent successfully  |
|
| Back to top |
|
 |
TheNullz How do I cheat?
Reputation: 0
Joined: 19 Feb 2010 Posts: 2
|
Posted: Fri Feb 19, 2010 8:47 pm Post subject: |
|
|
Your code is overly complicated
VirtualKeyCode = The actual keycode. You can either use the VK_* constants (defined in WinUser.h) or use a VkKeyScan function to get the virtual key code.
ScanCode = Should be obtained with a call to MapVirtualKey or MapVirtualKeyEx.
Your call to PostMessage for the Key down event should be similar to the following:
PostMessage(Hwnd, WM_KEYDOWN, VirtualKeyCode, ( ScanCode << 16 ) | 0x00100001);
Notice how we left shift the Scan Code. A multiplication operation is more expensive than a left shift operation.
Your call to PostMessage for the WM_KEYUP event should be similar to the following:
PostMessage(Hwnd, WM_KEYUP, VirtualKeyCode, ( ScanCode << 16 ) | 0xC1000001);
| Code: |
// SetLastError is the only field we need to set, because the default
// values for the other attribute fileds are the actual settings for the
// running version of windows.
[DllImport("user32.dll", SetLastError=true)]
public static extern int MapVirtualKey ( [In] int vKey, [In] int mapType );
// The WPARAM and LPARAM types used here are meaningless as long as they are at least 4-bytes wide.
[DllImport("user32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
pubic static extern bool PostMessage ( [In] IntPtr hWnd, [In] int Msg, [In] int wParam, [In] uint lParam);
public static void SendKey ( IntPtr hWnd, int vKey ) {
uint lParam = ( MapVirtualKey(vKey, 0) << 16 );
lParam &= 0x00FF00000; // single out our scan code byte
lParam |= 0x010000001; // set required bits
if ( !PostMessage(hWnd, WM_KEYDOWN, vKey, lParam) ) {
// Error handling code
}
lParam |= 0xC0000000;
if ( !PostMessage(hWnd, WM_KEYUP, vKey, lParam) ) {
// Error handling code
}
}
|
Last edited by TheNullz on Sun Feb 21, 2010 10:22 am; edited 1 time in total |
|
| Back to top |
|
 |
mibiz Cheater
Reputation: 0
Joined: 14 Jun 2009 Posts: 31
|
Posted: Sat Feb 20, 2010 1:58 pm Post subject: |
|
|
@TheNullz
Thanks for simplifying my code. Guess my programming knowledge and inexperience really shows. However, only the tab key works still .
This is the SS from Spy++ for AutoIt, which works as expected:
img85.imageshack.us/img85/1641/spyautoit.jpg
This is the SS from Spy++ for the adaptation of your simplified code:
img85.imageshack.us/img85/6760/spycs.jpg
This is the SS from Spy++ for the minor adjustment of the code to get the messages match:
img704.imageshack.us/img704/596/spycs2.jpg
One thing I've noticed is that the difference in Spy++ is the order of messages sent to the targeted game. AutoIt has WM_KEYDOWN, WM_CHAR, WM_KEYUP while my bot has WM_KEYDOWN, WM_KEYUP, WM_CHAR... I wonder if this is the cause of it. If that's the case, how can I fix the order? The code below is what I have now:
| Code: |
[DllImport("user32.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PostMessage([In] IntPtr hWnd, [In] int Msg, [In] int wParam, [In] uint lParam);
internal static void SendKey(int pid, string key)
{
DataRow[] rows = KeysTable.Select("Key='" + key + "'");
if (rows.Length == 1)
{
int vKey = (int)rows[0]["Code"];
IntPtr hWnd = Process.GetProcessById(pid).MainWindowHandle;
uint lParam = (uint)(MapVirtualKey(vKey, 0) << 16);
//lParam |= 0x00FF00000; // single out our scan code byte
//lParam |= 0x010000001; // set required bits
lParam |= 0x000000001; // set required bits
if (!PostMessage(hWnd, (int)KeyboardMessagesId.WM_KEYDOWN, vKey, lParam))
throw new Win32Exception(Marshal.GetLastWin32Error());
lParam |= 0xC0000000;
if (!PostMessage(hWnd, (int)KeyboardMessagesId.WM_KEYUP, vKey, lParam))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
} |
Thx,
/mibiz
PS: I can't post URLs yet  |
|
| Back to top |
|
 |
TheNullz How do I cheat?
Reputation: 0
Joined: 19 Feb 2010 Posts: 2
|
Posted: Sun Feb 21, 2010 10:35 am Post subject: |
|
|
Sorry dude, I wrote that in such a hurry I made a typo.
| Code: |
lParam |= 0x00FF00000; // single out our scan code byte
|
should be
| Code: |
lParam &= 0x00FF00000; // single out our scan code byte
|
WM_CHAR messages are utomatically dispatch to receiving program when it calls "TranslateMessage" on WM_KEYDOWN events. Even though you can send them yourself, you don't acually need to send a WM_CHAR message (its redundant).
Anyways, here's what you need to do:
1. Open up your program and begin spamming your keystrokes to your target. Using Spy++ (make sure you the raw message data option check) look at the WM_KEYDOWN messages that you program is sending to the target.
2. Close your program.
3. Type or move, or whatever in the target program.
4. Compare the the WM_KEYDOWN/WM_KEYUP messages between the ones generate by your program and the ones generated by your keyboard. They should have matching WPARAM and LPARAM values.
5. If they don't you're still sending the wrong parameters with your messages.
6. If they do, then the target program has some kind of protection against simulated keystrokes using PostMessage, OR the target application is checking the actual keyboard state for key strokes instead of just window messages (which is when you would investigate using SendInput calls).
Also, using MainWindowHandle, is a very poor way of getting the handle to your target window, and can lead to problems down the line. C# is a managed language, and as such, and pointers that you receive as properties of parameters should be cached in some kind of variable, incase they are disposed of prematurely or wiped to IntPtr.Zero by the underyling library or the CLR.
If the process ID is all you know about your target, then make a call to EnumWindows (if your target is a top-level window) or EnumChildWindows (if it is a child window) and use GetWindowThreadProcessId to match the PID against the one you want. |
|
| Back to top |
|
 |
mibiz Cheater
Reputation: 0
Joined: 14 Jun 2009 Posts: 31
|
Posted: Mon Feb 22, 2010 2:01 am Post subject: |
|
|
| TheNullz wrote: | Sorry dude, I wrote that in such a hurry I made a typo.
| Code: |
lParam |= 0x00FF00000; // single out our scan code byte
|
should be
| Code: |
lParam &= 0x00FF00000; // single out our scan code byte
|
WM_CHAR messages are utomatically dispatch to receiving program when it calls "TranslateMessage" on WM_KEYDOWN events. Even though you can send them yourself, you don't acually need to send a WM_CHAR message (its redundant).
Anyways, here's what you need to do:
1. Open up your program and begin spamming your keystrokes to your target. Using Spy++ (make sure you the raw message data option check) look at the WM_KEYDOWN messages that you program is sending to the target.
2. Close your program.
3. Type or move, or whatever in the target program.
4. Compare the the WM_KEYDOWN/WM_KEYUP messages between the ones generate by your program and the ones generated by your keyboard. They should have matching WPARAM and LPARAM values.
5. If they don't you're still sending the wrong parameters with your messages.
6. If they do, then the target program has some kind of protection against simulated keystrokes using PostMessage, OR the target application is checking the actual keyboard state for key strokes instead of just window messages (which is when you would investigate using SendInput calls).
Also, using MainWindowHandle, is a very poor way of getting the handle to your target window, and can lead to problems down the line. C# is a managed language, and as such, and pointers that you receive as properties of parameters should be cached in some kind of variable, incase they are disposed of prematurely or wiped to IntPtr.Zero by the underyling library or the CLR.
If the process ID is all you know about your target, then make a call to EnumWindows (if your target is a top-level window) or EnumChildWindows (if it is a child window) and use GetWindowThreadProcessId to match the PID against the one you want. |
Thanks for taking the time to help me resolve this problem. After fixing the code as per your suggestion, it's still not sending the any other key except the tab key. Below is the comparisons of Spy++ log between AutoIt and my code in C#:
| Code: | <00025> 001E0818 P WM_KEYDOWN nVirtKey:'1' cRepeat:1 ScanCode:02 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000031 lParam:00020001 time:42:28:33.646]
<00093> 001E0818 P WM_KEYDOWN nVirtKey:'1' cRepeat:1 ScanCode:02 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000031 lParam:00020001 time:42:35:45.706]
<00026> 001E0818 P WM_CHAR chCharCode:'0031' (49) cRepeat:1 ScanCode:02 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000031 lParam:00020001 time:42:28:33.646]
<00095> 001E0818 P WM_CHAR chCharCode:'0031' (49) cRepeat:1 ScanCode:02 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000031 lParam:00020001 time:42:35:45.753]
<00027> 001E0818 P WM_KEYUP nVirtKey:'1' cRepeat:1 ScanCode:02 fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000031 lParam:C0020001 time:42:28:33.646]
<00094> 001E0818 P WM_KEYUP nVirtKey:'1' cRepeat:1 ScanCode:02 fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000031 lParam:C0020001 time:42:35:45.706] |
It's still the same as before, everything matches except the order of the messages. AutoIt sends it to the targeted game in the proper(?) order WM_KEYDOWN, WM_CHAR, WM_KEYUP. Whereas my program sends it in the order WM_KEYDOWN, WM_KEYUP, WM_CHAR. I wonder if that's causing it the failure but then why did the tab key was sent successfully?
| Code: | <00099> 001E0818 P WM_KEYDOWN nVirtKey:VK_TAB cRepeat:1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000009 lParam:000F0001 time:42:35:46.252]
<00100> 001E0818 P WM_KEYUP nVirtKey:VK_TAB cRepeat:1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000009 lParam:C00F0001 time:42:35:46.252]
<00101> 001E0818 P WM_CHAR chCharCode:'0009' (9) cRepeat:1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000009 lParam:000F0001 time:42:35:46.268] |
As for the target app blocks input by doing several checks as you say (which I've thought about and researched when my code couldn't send the keys via low level hooks), then shouldn't AutoIt not work as also? Underlying source code for AutoIt is in C++ and it uses PostMessage(). The AutoIt uses VBSCript and then compiles that code to an exe or you run the script code from the editor. As for whether the game blocks input when not active window, that I've yet to confirm since the code I've written with AutoIt currently requires active window.
I'll research into SendInput and try using that to see if it works.
As for using MainWindowHandle, I'll take your advise and research on other methods and probably change my code accordingly. The reason why I used PID is I originally designed the app to support multiple games/client. The logic is already in place. Only thing left is implement sending keyboard & mouse to ensure the logic works as intended.
Thanks again,
mibiz |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|