📜 ⬆️ ⬇️

Remote mouse control using .NET Remoting

A couple of years ago I decided to try Remoting in combination with winapi and do remote mouse control. The solution should consist of 2 applications that interact through .NET Remoting. The server application must be in the form of a Windows service.

The server is similar to the RAdmin server, listens to the port and waits for the client to connect. When a client connects, the server accepts information about the need to change the position of the mouse or the click of a button.

The client, in turn, connects to the specified server and, if the mouse position changes in the client window, sends the information to the server.

At the moment I do not use Windows, so I will restore everything from memory.
')
I used remoting because At that time, it was a new interesting technology that allows you to abstract from the socket level and communicate to the client and server at the object / interface level. That is, instead of opening a socket, exchanging messages, we simply declare an object that we want to share on the server and use its methods on the client. If we compare the sockets with SQL and direct interaction with the database, then .NET Remoting is similar to ORM, a beautiful and convenient wrapper.

Customer


The client is simple to ugliness. When launching, we initialize Remoting, when we press the button, we connect to the server or disconnect from it. There is a window and a form on it. We intercept mouse movements on it and pressing / releasing the mouse button. The client knows only the interface with which he interacts, transfers to him in the functions the changes in our mouse.

Client Remoting Configuration

<configuration> <system.runtime.remoting> <application> <lifetime leaseTime="20D" sponsorshipTimeout="1H" renewOnCallTime="1D" leaseManagerPollTime="1H" /> <client> <wellknown type="Communication.Communication,Communication" url="tcp://127.0.0.1:8000/Communication.rem" /> </client> <channels> <channel ref="tcp" port="0" clientConnectionLimit="20" > </channel> </channels> </application> </system.runtime.remoting> <appSettings> <add key="RemotingUrl" value="tcp://127.0.0.1:8000/Communication.rem"></add> </appSettings> </configuration> 

Client code

Everywhere in the article - the code on Sharpe.
  public partial class Form1 : Form { public Form1() { InitializeComponent(); RemotingConfiguration.Configure("Client.config"); } ICommunication iCommunication; bool connected; private void button1_Click(object sender, EventArgs e) { if (!connected) { iCommunication = (ICommunication)Activator.GetObject(typeof(ICommunication), textBox4.Text); connected = true; iCommunication.Move(100, 100); button1.Text = ""; } else { button1.Text = ""; connected = false; } } private void panel1_MouseMove(object sender, MouseEventArgs e) { if (!connected) return; iCommunication.Move(eX, eY); } private void panel1_MouseDown(object sender, MouseEventArgs e) { if (!connected) return; iCommunication.Down(); } private void panel1_MouseUp(object sender, MouseEventArgs e) { if (!connected) return; iCommunication.Up(); } } 

At startup, we load the configuration, then, when we click on the button, we connect the remote object. When moving and clicking we call the corresponding function of this object.

Server


The server is a bit trickier. It has an object that implements the above interface, using .NET Remoting, it receives information about changes from the mouse and immediately sends winapi SendInput to change the position of the mouse and press its button (for several mouse buttons, passing keystrokes or a screen image is very simple change the given code - in the arguments we transfer to the server, and in the returned value we transfer to the client).

Server Remoting Configuration

 <configuration> <system.runtime.remoting> <application> <lifetime leaseTime="20D" sponsorshipTimeout="1H" renewOnCallTime="1D" leaseManagerPollTime="1H" /> <service> <wellknown mode="Singleton" type="Communication.Communication,Communication" objectUri="Communication.rem"/> </service> </application> </system.runtime.remoting> </configuration> 

The server is designed as a Windows service (when creating a template, select service).

In this case, the main function looks like this:
 static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); } 

Services are the same applications, but they run separately, have some privileges and special functions for starting / stopping. Such a special life cycle. Since this service must be launched on behalf of our user (to move the cursor), we change the user to the current one manually in the service control panel.

In our case, when the service starts, it must be initialized.

Server code

  public partial class Service1 : ServiceBase { public Service1() { InitializeComponent(); } Communication communication; protected override void OnStart(string[] args) { System.Runtime.Remoting.RemotingConfiguration.Configure(Application.StartupPath+"\\Server.config"); System.Runtime.Remoting.Channels.ChannelServices.UnregisterChannel(channel); BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider(); serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider(); System.Collections.IDictionary props = new System.Collections.Hashtable(); props["port"] = 8625; channel = new TcpChannel(props, clientProv, serverProv); System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(channel); communication = new Communication(); ObjRef or = RemotingServices.Marshal(communication, "Communication.rem"); communication.Move(100, 100); } TcpChannel channel; protected override void OnStop() { } } 

Here we see the service start function, in which Remoting is initialized. There is nothing to explain, we load the config, register the channel, register the object. You can use HTTP instead of TCP.

I took the ready cursor functions. It seems here .
And wrapped them in Communication:

 class Communication : MarshalByRefObject, ICommunication { //      –  winapi user32.dll,   –        } 

Everything, on the server, nothing else is needed, because this object will be managed through .NET Remoting

Add / Remove Service

There is an option to make a special installer for this service, but in my opinion it is easier to create 2 shortcuts with similar content:

For installation:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe "G:\current\location\our_service.exe"
For removing:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe "G:\current\location\our_service.exe" /u


This application has been tested on computers with Windows XP SP2. On older versions of Windows (Vista, 7), in my opinion, there are some glitches due to security, but this is solved.

It does not describe the server feedback mechanism with the client. Yes, you can make 2 connections - direct and inverse or periodically poll the server, but this is not very elegant. If you find this interesting, I will show you an elegant solution in the next article on this topic. There we will manage the point in the three-dimensional space so that the calculations were carried out on the server, and the display was carried out on the client. And then we will transfer the client part to Silverlight (already without Remoting, since the limitations of the silver do not allow it to be used) and display it in the browser.

Sources can be downloaded here .

Source: https://habr.com/ru/post/124491/


All Articles