Introduction
ezRemote makes Remote Desktop Work more easy and fast.
Background
Remote Desktop is very useful for managing remote computers.
I have decided to expand remote desktop to a level where user can do multiple
remote machine in one application.
In the article we are going to integrate remote desktop in
windows application using C#. To use finicality of remote desktop we are
going to use Microsoft Terminal Services Control Type Library. The purpose of
this application to manage all remote desktop connections at one place and have
facility to work with multiple connection from one application, provide easy to
maintain list of remote connection, search and delete options.
Points of Interest
- Can store all remote machine details at one place
- Search feature
- Tabbed look, can have multiple connection in one application same time
- Full screen feature
- Copy paste data
- Easy to use
- Can share connections with other, (From C:\autoremote, give your connection to other person so it reduces recreating)
- Encrypted connection files
External Library
To connect with remote machine I have used COM Component Microsoft
Terminal Services Control Type Library. You can add the com to toolbar from right
click on toolbar->Chose Items->Com Components (tab from new window). Now search for Terminal Services Control Type
Library, double click to add to toolbar.
Implementation
Add New Remote
Machine: To connect with any remote machine ip, username and password is
necessary. To save this information and use further in the software here a UI
is created. The main thing here is to save this information independently as
well as provide security. The information is saved as text file with .rtm extension
in C:\autoremote folder. The data is encrypted. The class used to encrypt
decrypt is as under.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace AutoRemote.BAL
{static public class Crypto
{
private static readonly byte[] salt = Encoding.ASCII.GetBytes("TrendMicro");
public static string Encrypt(string textToEncrypt)
{
string encryptionPassword = "IG";
var algorithm = GetAlgorithm(encryptionPassword);
byte[] encryptedBytes;
using (ICryptoTransform encryptor = algorithm.CreateEncryptor(algorithm.Key, algorithm.IV))
{
byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt);
encryptedBytes = InMemoryCrypt(bytesToEncrypt, encryptor);
}
return Convert.ToBase64String(encryptedBytes);
}
public static string Decrypt(string encryptedText)
{
string encryptionPassword = "IG";
var algorithm = GetAlgorithm(encryptionPassword);
byte[] descryptedBytes;
using (ICryptoTransform decryptor = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
{
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
descryptedBytes = InMemoryCrypt(encryptedBytes, decryptor);
}
return Encoding.UTF8.GetString(descryptedBytes);
}
private static byte[] InMemoryCrypt(byte[] data, ICryptoTransform transform)
{
MemoryStream memory = new MemoryStream();
using (Stream stream = new CryptoStream(memory, transform, CryptoStreamMode.Write))
{
stream.Write(data, 0, data.Length);
}
return memory.ToArray();
}
private static RijndaelManaged GetAlgorithm(string encryptionPassword)
{
var key = new Rfc2898DeriveBytes(encryptionPassword, salt);
var algorithm = new RijndaelManaged();
int bytesForKey = algorithm.KeySize / 8;
int bytesForIV = algorithm.BlockSize / 8;
algorithm.Key = key.GetBytes(bytesForKey);
algorithm.IV = key.GetBytes(bytesForIV);
return algorithm;
}
}
}
Connect With Remote Machines:
To provide multiple remote connections
on single application, tab control is used in application. For each new
connection request it search for already open connection; if not found it
create a new tab page and open new connection with the use of UserControl "CtlRemote
". CtlRemote
provides remote
desktop connection facility as well zoom and close facility.
private void dg_DoubleClick(object sender, EventArgs e)
{
if (dg.SelectedRows.Count > 0)
{
ManageTabs(dg.SelectedRows[0].Cells[0].Value.ToString(), dg.SelectedRows[0].Cells[1].Value.ToString(), dg.SelectedRows[0].Cells[2].Value.ToString(), dg.SelectedRows[0].Cells[0].Tag.ToString());
}
}
public void ManageTabs(string ip, string title, string username, string password)
{
try
{
panel2.Visible = false;
for (int i = 0; i <= tab1.TabPages.Count - 1; i++)
{
if (tab1.TabPages[i].Tag == ip)
{
tab1.TabPages[i].Select();
tab1.SelectedTab = tab1.TabPages[i];
return;
}
}
TabPage page = new TabPage();
CtlRemote remote = new CtlRemote();
page.Tag = ip;
page.ImageIndex = 0;
tab1.TabPages.Add(page);
page.Text = title + "[" + ip + "]";
remote.lblname.Text = title + "[" + ip + "]";
page.Controls.Add(remote);
remote.Visible = true;
remote.Dock = DockStyle.Fill;
tab1.TabPages[tab1.TabPages.Count - 1].Select();
tab1.SelectedTab = page;
remote.remote1.Server = ip;
remote.remote1.UserName = username;
IMsTscNonScriptable secured = (IMsTscNonScriptable)remote.remote1.GetOcx();
secured.ClearTextPassword = password;
remote.remote1.Connect();
remote.username = username;
remote.password = password;
remote.ip = ip;
}
catch (System.Exception ex)
{
AppUtils.Error(ex.ToString());
}
}
Manage Remote Connections: The software loads all the connection made by
user from the directory "C:\autoremote". When user crates or deletes any new
connection file is created or deleted. RemoteMachin
class is used for search
operation.
private void ListRemoteMachine()
{
try
{
RemoteMachine.list.Clear();
dg.Rows.Clear();
if (Directory.Exists(AppUtils.datapath) == false)
{
Directory.CreateDirectory(AppUtils.datapath);
}
DirectoryInfo dir = new DirectoryInfo(AppUtils.datapath);
FileInfo[] rf = dir.GetFiles();
for (int i = 0; i <= rf.Length - 1; i++)
{
if (Path.GetExtension(rf[i].FullName) == ".rmt")
{
string str = File.ReadAllText(rf[i].FullName);
string strnew = Crypto.Decrypt(str);
string[] tmp = Regex.Split(strnew, "<<<<999999<<<<");
string[] tmp2 = { tmp[0], tmp[1], tmp[2] };
dg.Rows.Add(tmp2);
dg.Rows[dg.Rows.Count - 1].Tag = rf[i].FullName;
dg.Rows[dg.Rows.Count - 1].Cells[0].Tag = tmp[3];
dg.Rows[dg.Rows.Count - 1].Cells[1].Tag = tmp[4];
RemoteMachine.list.Add(new RemoteMachine(tmp[0], tmp[1], tmp[2], tmp[4], tmp[5], rf[i].FullName));
}
}
}
catch (System.Exception ex)
{
AppUtils.Error(ex.ToString());
}
}
private void txtsearch_TextChanged(object sender, EventArgs e)
{
if (txtsearch.Text == "")
{
ListRemoteMachine();
}
else
{
dg.Rows.Clear();
List<RemoteMachine> list = RemoteMachine.GetList(txtsearch.Text);
for (int i = 0; i <= list.Count - 1; i++)
{
if (Path.GetExtension(list[i].FilePath) == ".rmt")
{
string[] tmp2 = { list[i].IP, list[i].Title, list[i].Username };
dg.Rows.Add(tmp2);
dg.Rows[dg.Rows.Count - 1].Tag = list[i].FilePath;
dg.Rows[dg.Rows.Count - 1].Cells[0].Tag = list[i].Password;
dg.Rows[dg.Rows.Count - 1].Cells[1].Tag = list[i].Description;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AutoRemote.BAL
{
class RemoteMachine
{
public static List<RemoteMachine> list = new List<RemoteMachine>();
public string IP, Title, Username, Password, Description, FilePath;
public RemoteMachine()
{
}
public RemoteMachine(string _IP, string _Title, string _Username, string _Password, string _Description, string _FilePath)
{
IP = _IP;
Title = _Title;
Username = _Username;
Password = _Password;
Description = _Description;
FilePath = _FilePath;
}
public static List<RemoteMachine> GetList(string search)
{
if (search == "")
{
return list;
}
search = search.ToLower();
var qry=from c in list
where c.IP.ToLower().Contains(search) || c.Title.ToLower().Contains(search)
select c;
return qry.ToList();
}
}
}