Mouse move automation in windows service - c#

I have created a Windows Service,
In the On start method, i am invoking a Listener for an input device
public class LeapMouseServiceService : ServiceBase
{
private Controller cnt;
private LeapListener ls;
public LeapMouseServiceService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.cnt.AddListener(ls);
}
MouseOpera has mouse_event from USer32.dll
class MouseOpera
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetCursorPos(int x, int y);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENTF_MOVE = 0x01;
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public static void DeltaMove(int x, int y)
{
mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);
}
LeapListener Class has Onframe method
class LeapListener : Listener
{
private Object thisLock = new Object();
System.IO.StreamWriter sw = new System.IO.StreamWriter(#"K:\logs\log.txt",true);
private void SafeWriteLine(String line)
{
lock (thisLock)
{
sw.WriteLine(line);
}
}
public override void OnInit(Controller controller)
{
SafeWriteLine(DateTime.Now.ToShortDateString());
SafeWriteLine("Initialized");
}
public override void OnConnect(Controller controller)
{
SafeWriteLine("Connected");
}
public override void OnDisconnect(Controller controller)
{
//Note: not dispatched when running in a debugger.
SafeWriteLine("Disconnected");
}
public override void OnExit(Controller controller)
{
SafeWriteLine("Exited");
}
public override void OnFrame(Controller controller)
{
// Get the most recent frame and report some basic information
Frame frame = controller.Frame();
MouseOpera.DeltaMove((int)(hand.Direction.Yaw*10),-(int)(hand.Direction.Pitch*10));
The log.txt is perfectly capturing all Leap activities when Service is running. But, the mouse movement is not happening. How to make the mouse move automatically from windows service using C# code?

Related

How can I avoid crashing when creating a precision timer with WinMM.dll?

I'm trying to create a precision timer. I found an example created with WinMM.dll. The sample works really fine. But it crashes with the first garbage collector.
How can I prevent the garbage collector from blocking the timer?
public class WinMMWrapper : IDisposable
{
[DllImport("WinMM.dll", SetLastError = true)]
public static extern uint timeSetEvent(int msDelay, int msResolution,
TimerEventHandler handler, ref int userCtx, int eventType);
[DllImport("Winmm.dll", CharSet = CharSet.Auto)] // <=== ADD THIS
static extern uint timeKillEvent(uint uTimerID); // <=== ADD THIS
public delegate void TimerEventHandler(uint id, uint msg, ref int userCtx,
int rsv1, int rsv2);
public enum TimerEventType
{
OneTime = 0,
Repeating = 1,
}
private readonly Action _elapsedAction;
private readonly int _elapsedMs;
private readonly int _resolutionMs;
private readonly TimerEventType _timerEventType;
private uint _timerId; // <=== ADD THIS
private bool _disposed; // <=== ADD THIS
public WinMMWrapper(int elapsedMs, int resolutionMs, TimerEventType timerEventType, Action elapsedAction)
{
_elapsedMs = elapsedMs;
_resolutionMs = resolutionMs;
_timerEventType = timerEventType;
_elapsedAction = elapsedAction;
}
public bool StartElapsedTimer() // <=== RETURN bool
{
StopTimer(); // Stop any started timer
int myData = 1;
// === SET _timerId
_timerId = timeSetEvent(_elapsedMs, _resolutionMs / 10, new TimerEventHandler(TickHandler), ref myData, (int)_timerEventType);
return _timerId != 0;
}
public void StopTimer() // <=== ADD THIS
{
if (_timerId != 0)
{
timeKillEvent(_timerId);
_timerId = 0;
}
}
private void TickHandler(uint id, uint msg, ref int userctx, int rsv1, int rsv2)
{
_elapsedAction();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!_disposed && disposing)
StopTimer();
_disposed = true;
}
~WinMMWrapper()
{
Dispose(false);
}
}
My Static Class
public static class Global
{
public static WinMMWrapper timer;
}
Create WinMMWrapper
private void TimerStart_Click(object sender, RoutedEventArgs e)
{
Global.timer = new WinMMWrapper(1, 1, WinMMWrapper.TimerEventType.Repeating, Tick);
Global.timer.StartElapsedTimer();
}
Tick Function
private static void Tick()
{
Console.WriteLine("Time : " + DateTime.Now.ToString("hh:mm:ss:ffff"));
}
Error Message
Managed Debugging Assistant 'CallbackOnCollectedDelegate' : A callback was made on the garbage-collected delegate of type 'CanBusRandomDataGenerator!CanBusRandomDataGenerator.WinMMWrapper+TimerEventHandler::Invoke'. This can cause app crashes, corruption, and data loss. When delegating to unmanaged code, it must be kept alive by the managed application until it is guaranteed that the delegates will never be called.'
The code is now exactly the same. It works for about 2 3 seconds, then it crashes to the following error. Error occurs within WinMMWrapper function without falling into Dispose.
You must keep the timer variable alive as long as you are using the timer. If it is a local variable, it will be reclaimed by the GC when you leave the method. Do so by converting this local variable to a class field (possibly static). In a Console application you can still use a local variable, but you must add a Console.ReadKey(); to prevent the application to exit prematurely.
Also, stop the timer before this variable becomes eligible for garbage collection. To do so, let WinMMWrapper implement IDisposable.
Make sure that the object where the callback Action lives stays alive and is not disposed! Probably this is the object where you call new WinMMWrapper(..., theAction).
public class WinMMWrapper : IDisposable
{
[DllImport("WinMM.dll", SetLastError = true)]
public static extern uint timeSetEvent(int msDelay, int msResolution,
TimerEventHandler handler, ref int userCtx, int eventType);
[DllImport("Winmm.dll", CharSet = CharSet.Auto)] // <=== ADD THIS
static extern uint timeKillEvent(uint uTimerID); // <=== ADD THIS
public delegate void TimerEventHandler(uint id, uint msg, ref int userCtx,
int rsv1, int rsv2);
public enum TimerEventType
{
OneTime = 0,
Repeating = 1,
}
private readonly Action _elapsedAction;
private readonly int _elapsedMs;
private readonly int _resolutionMs;
private readonly TimerEventType _timerEventType;
private iuint _timerId; // <=== ADD THIS
private bool _disposed; // <=== ADD THIS
public WinMMWrapper(int elapsedMs, int resolutionMs, TimerEventType timerEventType, Action elapsedAction)
{
_elapsedMs = elapsedMs;
_resolutionMs = resolutionMs;
_timerEventType = timerEventType;
_elapsedAction = elapsedAction;
}
public bool StartElapsedTimer() // <=== RETURN bool
{
Stop(); // Stop any started timer
int myData = 1;
// === SET _timerId
_timerId = timeSetEvent(_elapsedMs, _resolutionMs / 10, new TimerEventHandler(TickHandler), ref myData, (int)_timerEventType);
return _timerId != 0;
}
public void StopTimer() // <=== ADD THIS
{
if (_timerId != 0)
{
timeKillEvent(_timerId);
_timerId = 0;
}
}
private void TickHandler(uint id, uint msg, ref int userctx, int rsv1, int rsv2)
{
_elapsedAction();
}
// === ADD Dispose and finalizer ===
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!_disposed && disposing)
StopTimer();
}
_disposed = true;
}
~MMTimer()
{
Dispose(false);
}
}
Then you can do this in a Console application:
using (var timer = new WinMMWrapper(1, 1, WinMMWrapper.TimerEventType.Repeating,
() => Console.WriteLine("Time : " + DateTime.Now.ToString("hh:mm:ss:fff"))) {
Console.Writeline("Hit a key to stop the timer and quit the application!");
Console.ReadKey();
} // <= Here timer.Dispose() gets automatically called by using.
If you cannot use a using statement because your timer will be stopped at another place in your code, you can also call timer.Dispose(); explicitly.
To make this code thread-safe, enclose your start and stop timer code in a lock(this { ... } statement.

Invoke error why trying to run autoclicker

I want to make an autoclicker that will click when i press "F" button; But each time I try to press "F" I get invoke error.
I tried to run Click thread in another void but it didn't work.
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
UserActivityHook actHook;
static bool autoclickerToggle = false;
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public Form1()
{
InitializeComponent();
actHook = new UserActivityHook(); // crate an instance with global hooks
// hang on events
actHook.OnMouseActivity += new MouseEventHandler(MouseMoved);
actHook.KeyDown += new KeyEventHandler(MyKeyDown);
actHook.KeyPress += new KeyPressEventHandler(MyKeyPress);
actHook.KeyUp += new KeyEventHandler(MyKeyUp);
}
public void MouseMoved(object sender, MouseEventArgs e) { }
public void MyKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F)
{
AutoclickerToggle();
}
}
public void MyKeyPress(object sender, KeyPressEventArgs e) { }
void AutoclickerToggle()
{
if (autoclickerToggle)
{
autoclickerToggle = false;
}
else
{
autoclickerToggle = true;
Thread Click = new Thread(() => Clicker());
Click.Start();
}
}
public void MyKeyUp(object sender, KeyEventArgs e) { }
public void Clicker()
{
while (autoclickerToggle)
{
int X = Cursor.Position.X;
int Y = Cursor.Position.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
Thread.Sleep(100);
}
}
As I said I've got this error when pressing "F" (used translator there, because I had this error in polish language) "Calling PInvoke 'Test! Test.Form1 :: mouse_event 'has upset the balance of the stack. The likely cause is a mismatch between the managed PInvoke signature and the unmanaged target signature. Verify that the called convention and signature parameters of the PInvoke function match the unmanaged destination signature"

C# how to toggle simulated mouse clicks with left mouse button

I would like to so when I hold my left mouse button down it simulates clicks but this is not working as it's not simulating clicks but if I remove the if statement in the timer1, it simulates clicks but I want it to only simulate when I'm holding left mouse.
Here is my code so far what I've done. if you could help that would be great
public partial class Form1 : Form
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
//Mouse actions
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Stop();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (MouseButtons == MouseButtons.Left){
DoMouseClick();
}
}
public void DoMouseClick()
{
//Call the imported function with the cursor's current position
uint X = (uint)Cursor.Position.X;
uint Y = (uint)Cursor.Position.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
}

Middle button click to scroll

How do I achieve this in a WinForms container control when the scroll bars are visible?
Highlighted here (Google Chrome browser):
EDIT: This cursor is the only one that is visible on a screenshot. I hope it's clear what i mean.
EDIT:
Tried this on my control. Does not work.
const int WM_MBUTTONDOWN = 0x207;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MBUTTONDOWN)
DefWndProc(ref m);
else
base.WndProc(ref m);
}
Here's what I have so far. It exits "reader mode" if I release the middle button, and I haven't implemented scrolling within the control (I used a textbox), but it may give you something to start with.
[DllImport("comctl32.dll", SetLastError=true, EntryPoint="#383")]
static extern void DoReaderMode(ref READERMODEINFO prmi);
public delegate bool TranslateDispatchCallbackDelegate(ref MSG lpmsg);
public delegate bool ReaderScrollCallbackDelegate(ref READERMODEINFO prmi, int dx, int dy);
[StructLayout(LayoutKind.Sequential)]
public struct READERMODEINFO
{
public int cbSize;
public IntPtr hwnd;
public int fFlags;
public IntPtr prc;
public ReaderScrollCallbackDelegate pfnScroll;
public TranslateDispatchCallbackDelegate fFlags2;
public IntPtr lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public UInt32 message;
public IntPtr wParam;
public IntPtr lParam;
public UInt32 time;
public POINT pt;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}
private bool TranslateDispatchCallback(ref MSG lpMsg)
{
return false;
}
private bool ReaderScrollCallback(ref READERMODEINFO prmi, int dx, int dy)
{
// TODO: Scroll around within your control here
return false;
}
private void EnterReaderMode()
{
READERMODEINFO readerInfo = new READERMODEINFO
{
hwnd = this.textBox1.Handle,
fFlags = 0x00,
prc = IntPtr.Zero,
lParam = IntPtr.Zero,
fFlags2 = new TranslateDispatchCallbackDelegate(this.TranslateDispatchCallback),
pfnScroll = new ReaderScrollCallbackDelegate(this.ReaderScrollCallback)
};
readerInfo.cbSize = Marshal.SizeOf(readerInfo);
DoReaderMode(ref readerInfo);
}
private void textBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Middle)
{
EnterReaderMode();
}
}
The RichTextBox control does it by default when you press the mouse wheel button.
Edit: Sorry I misunderstood and thought you were asking about doing it within a textbox not a container control

Scrollbar flicker when calling EnableScrollBar

I'm using p/invoke to call EnableScrollBar from user32.dll (MSDN reference). I noticed that when the scrollbar is enabled, it seems to draw as though no theme is applied and then re-drawn with the theme applied. I've only tested with Windows 7 so far. Is there
any way to stop this from happening?
EDIT: Here's some code to show what happens (dump into a form with scrollbars):
private class Native
{
[DllImport("user32.dll")]
public static extern bool EnableScrollBar(IntPtr hWnd, uint wSBflags, uint wArrows);
public static class SBArrows
{
public const uint ESB_ENABLE_BOTH = 0;
public const uint ESB_DISABLE_BOTH = 3;
public const uint ESB_DISABLE_LEFT = 1;
public const uint ESB_DISABLE_RIGHT = 2;
public const uint ESB_DISABLE_UP = 1;
public const uint ESB_DISABLE_DOWN = 2;
public const uint ESB_DISABLE_LTUP = 1;
public const uint ESB_DISABLE_RTDN = 2;
}
public static class SBFlags
{
public const uint SB_HORZ = 0;
public const uint SB_VERT = 1;
public const uint SB_CTL = 2;
public const uint SB_BOTH = 3;
}
}
private bool Switch = false;
protected override void OnMouseDown(MouseEventArgs e)
{
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, this.Switch ? Native.SBArrows.ESB_DISABLE_BOTH : Native.SBArrows.ESB_ENABLE_BOTH);
this.Switch = !this.Switch;
}
Final Solution
Native.SendMessage(this.Handle, Native.WindowMessages.WM_SETREDRAW, new IntPtr(0), IntPtr.Zero);
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, Native.SBArrows.ESB_ENABLE_BOTH);
Native.SendMessage(this.Handle, Native.WindowMessages.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
I don't like this solution much. It does however work:
protected override void OnMouseDown(MouseEventArgs e) {
Native.LockWindowUpdate(this.Handle);
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, this.Switch ? Native.SBArrows.ESB_DISABLE_BOTH : Native.SBArrows.ESB_ENABLE_BOTH);
//this.Invalidate();
Native.LockWindowUpdate(IntPtr.Zero);
this.Switch = !this.Switch;
}

Categories

Resources