Having run into a number of things I cannot accomplish with InSim in LFS, I’ve decided to venture down the ugly route of simulating the mouse. Not that horrible. InSim was never really designed for client automation.
I haven’t tested this on LFS yet, just Calc.exe, but I finally found a way to do mouse clicks in another application from .NET.
The first route i went down was the SendMessage from user32.dll. Tried many different ways of getting the windowhandle and all that stuff, but no click ever materialized. Also found this method weird. Why do i have to tell it what window i’m clicking when i give it the cursor position. It’s likely i just never figured out the proper syntax, but the docs i found certainly didn’t aid me much.
Then i found mouse_event also from user32.dll. This one just sent a click event for the current location of the mouse. Just the way i would have expected. And it works!
Here’s the sample code:
const int WM_LBUTTONDOWN = 0x0201; const int WM_LBUTTONUP = 0x0202; const int SC_MAXIMIZE = 0xF030; const UInt32 MouseEventLeftDown = 0x0002; const UInt32 MouseEventLeftUp = 0x0004; [DllImport("user32.dll", EntryPoint="SendMessage", CharSet=CharSet.Auto)] public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); [DllImport("user32.dll")] static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo); public static void Test() { Process myProc = new Process(); myProc.StartInfo.FileName = @"calc.exe"; myProc.Start(); // maximizing so we know where the button is (cheap ass hack for testing) SendMessage(myProc.MainWindowHandle,WM_SYSCOMMAND,SC_MAXIMIZE,0); Point p = new Point(150,150); // the 6 button Cursor.Position = p; Thread.Sleep(1000); if (myProc.WaitForInputIdle(3000)) { // This one works !!! mouse_event(MouseEventLeftDown,0,0,0,new System.UIntPtr()); mouse_event(MouseEventLeftUp,0,0,0,new System.UIntPtr()); // This one doesn't do anythingSendMessage(myProc.MainWindowHandle,WM_LBUTTONDOWN, Cursor.Position.X, Cursor.Position.Y); SendMessage(myProc.MainWindowHandle,WM_LBUTTONDOWN, Cursor.Position.X, Cursor.Position.Y); } }
I was this close to just using ISerializable for by binary representation for networking. But then talking to n8, i decided that leaving the door open for java interop was important enough in Enterprise computing, that I couldn’t ignore it.
So, I’m back to coming up with my packet structure in manner that i can easily serialize by hand. Right now the plan is something along the line of a fixed sized header followed by a variable sized gzip-Xml chunk and a variable sized raw data chunk. Both of the variable chunks can be 0 length. The header is used for expressing the purpose of the packet, and describing the offsets of the variable packets. The gzip-Xml is for data that the recipient is supposed to parse and act on, while the raw data packet will be just that, raw data that i sued to construct a complete file.
I need to dig up the test code i did for doing manual serialization in .NET. Really, just what would be done in C with a struct and memcpy, but of course, since in C# you don’t have pointers and the memory is managed for you, it’s a bit more of a hoop jumping exercise. The code is on another machine, so i’ll leave that for another post.